2

I was reading this page (the factories section in particular).

It mentions to avoid using the new keyword to prevent the case of accidently forgetting it. It suggests using factories.

Page's new Example:

function Bar() {
    var value = 1;
    return {
        method: function() {
            return value;
        }
    }
}
Bar.prototype = {
    foo: function() {}
};

new Bar(); 
Bar(); // These are the same.

Page's factory example:

function Foo() {
    var obj = {};
    obj.value = 'blub';

    var private = 2;
    obj.someMethod = function(value) {
        this.value = value;
    }

    obj.getPrivate = function() {
        return private;
    }
    return obj;
}

Factory Cons:

  • It uses more memory since the created objects do not share the methods on a prototype.
  • In order to inherit, the factory needs to copy all the methods from another object or put that object on the prototype of the new object.
  • Dropping the prototype chain just because of a left out new keyword is contrary to the spirit of the language.

The avoiding new to prevent issues in case you forget is understandable. But what I'm not quite grasping is that they say the factory example takes more memory since it's not using the prototype functions. So why not use something like this instead?

My Solution:

var Foo = function () {
    var foo = function () {

    };
    foo.prototype = {
        bar: function () { }
    };
    return new foo();
};

Question: Am I missing something that makes this not a better solution? Does my solution remove the listed cons of the factory method, why or why not?

3
  • 1
    Yes this creates a new constructor every time you call the factory method Commented Jul 17, 2014 at 21:09
  • I clarified my question a bit. I knew mine created a new object each time, I just was curious if it removed the factory-method cons that were listed by linked site (which I included in my question now). Or added any pros/cons for that matter. Commented Jul 17, 2014 at 21:13
  • Don't belief them! As all these code snippets show, there are worse thing that can go wrong. There are better ways to counter forgotten news. Commented Jul 17, 2014 at 22:00

1 Answer 1

1

Alright, let's take the new example:

function Bar() {
    var value = 1;
    // Whoops, sorry
    // As Bergi points out, if you have a return value then that overrides the normal object that is returned by new
    // Didn't even notice you have a return in here!
    /*
    return {
        method: function() {
            return value;
        }
    }
    */
    // This does the same thing (approximately) but now calling "(new Bar()) instanceof Bar" will be true
    this.method = function() {
        return value;
    };
}
Bar.prototype = {
    foo: function() {}
};

var b = new Bar();

In the google chrome console, b has a property called __proto__. Basically, when you call b.foo(), first the browser looks for a method called foo. If it doesn't find it, it looks in b.__proto__ and b.__proto__.__proto__ and so on.

Notice: b.__proto__ === Bar.prototype

That means if you call new Bar() repeatedly, they will all have the same __proto__, which saves memory. (This has the side effect of, if you mutate Bar.prototype, it will change all instances of Bar's __proto__ as well).

Let's look at your factory method:

var Foo = function () {
    var foo = function () {

    };
    foo.prototype = {
        bar: function () { }
    };
    return new foo();
};

This doesn't save memory because it creates a new prototype, and a new constructor every time you call Foo(). So in other words, if

var f1 = new Foo(), f2 = new Foo();

The following return false: f1.constructor == f2.constructor and f1.__proto__ == f2.__proto__. What does this mean? It means that f1 and f2 don't share the same prototype so the objects have to be duplicated every time. Perhaps, you could do this:

var fooProto = {
  callFoo: function() { alert("test"); }
};
function Foo() {
    var foo = function() {};
    foo.prototype = fooProto;
    return new foo();
};

This would use the same amount of memory as the regular constructor.

Side edit: Modern browsers have a built-in function that does something like Foo in the last example. You could use Object.create(fooProto) (but only in newer browsers).

Also, note that __proto__ is technically a hidden, read-only property (although some browsers let you write to it). It was only used for the sake of showing what goes on behind the scenes, and it shouldn't be used in real code.

Sign up to request clarification or add additional context in comments.

6 Comments

1. Would moving the foo & foo.prototype outside of the Foo function solve that? 2. Thanks for explaining about __proto__ was helpful.
b.__proto__ === Bar.prototype - uh,no? The constructor returns an object, the prototype will be ignored.
You just should always use Object.create, for clarity. And shim it in older browsers if necessary.
@Bergi (comment 1) I'm talking about the first example, where you use var b = new Bar();. Then b.__proto__ === Bar.prototype
@Shelby115: Yes, it would help. Actually it's not even so uncommon to have a function makeFoo() { return new Foo(); } that can - in contrast to Foo - be used without new. Notice that constructor names should always be capitalized.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.