Domanda

I am trying to work out how to instantiate a new object from another instantiated object without without using the new operator. The following code below works but I hear the __proto__ property is depreciated.

var MyObject = function( arg ) {

    this.value = arg;

};

MyObject.prototype.getValue = function() {

    return this.value;

};

// Standard way of instantiating an object
var object1 = new MyObject( 'foo' );

// Creating new object based on another without using new operator
var object2 = {};
object2.__proto__ = object1.__proto__
object1.constructor.call( object2, 'bar' );

console.log( object1 );
console.log( object2 );

So how would I do this without the __proto__ property?

È stato utile?

Soluzione 2

As thefourtheye mentioned, changing the [[Prototype]] of an object after it is created is strongly discourged.

However, in your use case you don't really have a reason to change the [[Prototype]] at a random point in an object's lifetime, but instead you want to create an object with a given [[Prototype]].

The method that accomplishes this is Object.create, which creates an object with a specified [[Prototype]] value:

var object2 = Object.create(object1);
object1.constructor.call(object2, 'bar');

If your desired environment doesn't support Object.create, a shim is available on the MDN page. While imperfect (not all functionality is covered), the shim does exactly what you need in this scenario.

Altri suggerimenti

Quoting from __proto__'s MDN Docs,

The __proto__ property is deprecated and should not be used. Object.getPrototypeOf should be used instead of the __proto__ getter to determine the [[Prototype]] of an object. Mutating the [[Prototype]] of an object, no matter how this is accomplished, is strongly discouraged, because it is very slow and unavoidably slows down subsequent execution in modern JavaScript implementations. However, Object.setPrototypeOf is provided in ES6 as a very-slightly-preferred alternative to the __proto__ setter.

But your actual code works, let us see why.

  1. First of all, any object which is created with an Object literal will have its __proto__ property as the same as Object.prototype. You can check this like this

    var object2 = {};
    console.log(object2.__proto__ === Object.prototype);
    # true
    
  2. Since object1 is created with MyObject function, the following is true

    console.log(object1.__proto__ === MyObject.prototype);
    # true
    
  3. When you say

    object2.__proto__ = object1.__proto__;
    

    From 2, we can see that it is the same as,

    object2.__proto__ = MyObject.prototype;
    

    so, you are just making JavaScript believe that, object2 is also an object of MyObject.

  4. Since we assigned MyObject's prototype to object1's prototype, constructor of both the objects are the same

    console.log(object1.constructor === object2.constructor);
    
  5. And then you are calling the MyObject function with object2 as this.

    object1.constructor.call( object2, 'bar' );
    

Since changing __proto__ is NOT recommended, the best way to do this would be to use new keyword only

var object1 = new MyObject('foo'),
    object2 = new MyObject('bar');

But, lets say you have got only object1, but not the definition of MyObject. Then, you can make use of the constructor property like this

object2 = new object1.constructor('bar');

It appears the latest draft of ECMAScript 6 has standardized __proto__. See section B.2.2.1 of https://people.mozilla.org/~jorendorff/es6-draft.html.

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