什么已经取代了JavaScript中已弃用的__proto__

时间:2014-04-03 07:44:31

标签: javascript prototype

我试图找出如何在不使用new运算符的情况下从另一个实例化对象实例化新对象。下面的代码有效,但我听说__proto__属性已被折旧。

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 );

那么如果没有__proto__属性我该如何做呢?

3 个答案:

答案 0 :(得分:7)

引自__proto__'s MDN Docs

  

不推荐使用__proto__属性,不应使用该属性。应使用Object.getPrototypeOf代替__proto__ getter来确定对象的[[Prototype]]。强烈建议不要改变对象的[[Prototype]],无论如何实现,因为它非常慢并且不可避免地减慢了现代JavaScript实现中后续执行的速度。但是,Object.setPrototypeOf在ES6中作为__proto__ setter的一个非常优选的替代方案提供。

但是你的实际代码是有效的,让我们看看为什么。

  1. 首先,使用Object文字创建的任何对象都将__proto__属性与Object.prototype相同。您可以像这样检查

    var object2 = {};
    console.log(object2.__proto__ === Object.prototype);
    # true
    
  2. 由于使用object1函数创建MyObject,因此以下情况属实

    console.log(object1.__proto__ === MyObject.prototype);
    # true
    
  3. 当你说

    object2.__proto__ = object1.__proto__;
    

    从2开始,我们可以看到它与

    相同
    object2.__proto__ = MyObject.prototype;
    

    所以,您只是让JavaScript相信,object2也是MyObject的对象。

  4. 由于我们已将MyObject的原型分配给object1原型,因此两个对象的constructor相同

    console.log(object1.constructor === object2.constructor);
    
  5. 然后您使用MyObject作为object2来调用this函数。

    object1.constructor.call( object2, 'bar' );
    
  6. 由于不建议更改__proto__,因此最好的方法是仅使用new关键字

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

    但是,假设您只有object1,而不是MyObject的定义。然后,您可以使用constructor这样的属性

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

答案 1 :(得分:3)

作为thefourtheye mentioned,在创建对象后更改对象的[[Prototype]]会受到严重破坏。

但是,在您的用例中,您并没有理由在对象的生命周期中随机点更改[[Prototype]],而是想要创建一个具有给[[原型]]。

实现此目的的方法是Object.create,它创建一个具有指定[[Prototype]]值的对象:

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

如果您所需的环境不支持Object.create,则MDN页面上会有一个垫片。虽然不完美(并未涵盖所有功能),但垫片完全符合您在此场景中的需要。

答案 2 :(得分:3)

ECMAScript 6的最新草案似乎标准化为__proto__。见https://people.mozilla.org/~jorendorff/es6-draft.html的B.2.2.1节。