7

I am trying to solve a code challenge for a job app, but I am stuck and would appreciate any help.

Question: Create a class Foo that has a method called refCount. Calling refCount on the class or any of its instances should return how many total instances exists.

Example:

var f1 = new Foo();

f1.refCount(); // should be 1
Foo.refCount(); // should be 1

var f2 = new Foo();

f1.refCount(); //should be 2
f2.refCount(); // should be 2
Foo.refCount(); // should be 2

I have something like this so far:

function Foo() {

  this.refCount = function() {
    ++Foo.prototype.refs;
    return Foo.prototype.refs;
  }

}

Foo.prototype.refs = 0;

I also tried using an IIFE to attach a method to the class itself, but then I was unable to figure out how to create new instances.

zerkms
  • 249,484
  • 69
  • 436
  • 539
  • 2
    You have to increase the counter in the constructor, not in the counting method. Regardless, it's a silly challenge, it should not be a classes responsibility to keep track of its instances. – Bergi May 10 '16 at 22:40
  • 1
    @zerkms: That doesn't really matter, does it? – Bergi May 10 '16 at 22:41
  • @Bergi that does not, what I said makes no(t much) sense. – zerkms May 10 '16 at 22:41

3 Answers3

2

That cannot be done.

JavaScript is object-oriented, and classes in JavaScript are just an illusion, created by setting an object's prototype property to a certain prototype object.

The new Foo() syntax is syntactic sugar for setting that prototype. And your best option, as others have shown, is to do the refCounting in the constructor function, effectively counting the amount of times that it got called. You can then store the count variable in the prototype or as a property of the constructor function itself or in an IIFE (see below), and return its value in the refCount function.

But if people start dynamically changing the object's prototypes, the objects can change class and I can think of no way for the refCount function to know that that happened.

var Foo

(function(){
  var n = 0;
  Foo = function Foo() {
    this.refCount = Foo.refCount;
    n++;
  };
  Foo.refCount = function() {
    return n;
  }
})()

function Bar() {}

f = new Foo();
console.log("created f, refCount = 1", f instanceof Foo, f.refCount(), Foo.refCount());

g = new Foo();

console.log("created g, refCount = 2", f instanceof Foo, g instanceof Foo, f.refCount(), g.refCount(), Foo.refCount());

g.__proto__ = Bar.prototype;
console.log("turned g into a Bar", f instanceof Foo, g instanceof Foo)
console.log("but refCount still is 2", Foo.refCount());

h = Object.assign(f)
console.log("created h without calling the constructor", h instanceof Foo)
console.log("But refCount still is 2", h.refCount(), Foo.refCount())

See it on JSBin

See https://developer.mozilla.org/en/docs/Web/JavaScript/Inheritance_and_the_prototype_chain and How to set the prototype of a JavaScript object that has already been instantiated?

Community
  • 1
  • 1
flup
  • 26,937
  • 7
  • 52
  • 74
1
function Foo() {
    Foo.__n++;
}
Foo.refCount = function() { return Foo.__n; }
Foo.__n = 0;
Foo.prototype.refCount = Foo.refCount;

Output:

> var f = new Foo(); console.log(f.refCount(), Foo.refCount());
1 1
> f = new Foo(); console.log(f.refCount(), Foo.refCount());
2 2
> f = new Foo(); console.log(f.refCount(), Foo.refCount());
3 3
OneOfOne
  • 95,033
  • 20
  • 184
  • 185
  • That counts the amount of times the constructor was called, but it's not completely the same as the amount of class instances that exist. Best to also add some examples of what would break this solution? – flup May 10 '16 at 23:22
  • 1
    Thanks for the solution. I've never seen someone add properties to functions like that. – user6317504 May 11 '16 at 00:17
  • @user6317504 once you accept that "everything" is an object in javascript, you unlock a magical and a glorious world! – OneOfOne May 11 '16 at 02:04
  • I've added a couple examples showing a couple ways in which this will break. – flup May 11 '16 at 07:05
0
var n = refs = 0;

function refCount() {
  refs = ++n;
  return n;
}

function Foo() {
  refCount()
}

var f1 = new Foo();
console.log(refs);

var f2 = new Foo();
console.log(refs);
guest271314
  • 1
  • 15
  • 104
  • 177