Domanda

I've been reading Is JavaScript's "new" keyword considered harmful? and this Adobe Article on using prototypal inheritance rather than 'new'. The Adobe article has a 'new' example:

function Foo() {
    this.name = "foo";
}
Foo.prototype.sayHello = function() {
    alert("hello from " + this.name);
};

...that it replaces with:

var foo = {
    name: "foo",
    sayHello: function() {
        alert("hello from " + this.name);
    }
};

Here the 'sayHello' method isn't attached to the object's prototype. Doesn't this mean 'sayHello' gets unnecessarily duplicated in memory (I know V8 avoids this, but in older JS engines, for example) as it is copied to all objects that inherit from foo?

Shouldn't it be:

var foo = {
    name: "foo",
    prototype: {
        sayHello: function() {
            alert("hello from " + this.name);
        }
    }
};

Or similar?

È stato utile?

Soluzione

The method is not attached to the prototype because this very object becomes the prototype that is attached to newly created objects with Object.create. And you don't need a prototype of the prototype.

Remember that Object.create doesn't deep clone objects. Rather, it is equivalent to something like

Object.create = function(proto) {

   function F() {}
   F.prototype = proto;
   return new F();

}

(actual implementation is more complicated but this short version illustrates the idea)

All newly created objects "inherit" the method from the foo which acts as the prototype and there is no duplication here.

Altri suggerimenti

No, it won't get duplicated if you create another object using that as a protoype. The almost equivalent code using Object.create is actually slightly different, you are not using the prototype, you are just creating an object. To use prototypal inheritance, do the following. Note that using new still sets up the prototype chain so the title of the article you linked to is not very accurate and you are still sharing the properties on a single object.

var foo = {
    name: "foo",
    sayHello: function() {
        alert("hello from " + this.name);
    }
};

var extended = Object.create(foo);
var extended2 = Object.create(foo);

extended.name = "first";
extended2.name = "second";
extended.sayHello();  // hello from first
extended2.sayHello(); // hello from second

// Methods are shared, outputs true
console.log(extended.sayHello === extended2.sayHello)

// Now if you delete the property again, it will go up the chain
delete extended.name;
extended.sayHello(); // hello from foo

You could also just do

var extended = Object.create(Foo.prototype);

It would get duplicated if you create a constructor to get new instances instead of Object.create or new Foo

function createFoo() {
    return {
        name: "foo",
        sayHello: function() {
             alert("hello from " + this.name);
        }
    }
}

var a = createFoo();
var b = createFoo();
 // The function objects are not shared    
alert('Are functions the same? ' + a.sayHello === b.createFoo);

They would also not be shared if you use the closure approach to creating objects. Crockford suggests that to create truly private members. I don't use it because it doesn't use the prototype chain and inheritance is tricky to implement without just copying properties.

Function Foo() {
    var name = 'foo';
    this.sayHello = function () {
        alert(name);
    };
    this.setName = function (newName) {
        name = newName;
    };
}

var a = new Foo();
var b = new Foo();
console.log(a.sayHello === b.sayHello); // outputs false

Going to answer my own question here, for my own notes and also to help explain to others:

Q. Using Object.create(), should exemplars have methods attached to their prototype property?

A. No, because Object.create(parentObject) itself sets up the parentObject as the prototype of a dynamically-created constructor.

Also: prototype is always a property on constructor Functions - not on regular Objects. Eg:

var someArray = [];
someArray.__proto__ === Array.prototype

Object.create() dynamically creates constructors, setting the prototype on them to the object in its first argument.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top