JavaScript中已经废弃的__proto__被什么所取代?

4
我正在尝试弄清如何在不使用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个回答

8
引用自 __proto__ 的 MDN 文档

__proto__ 属性已过时,不应再被使用。应使用 Object.getPrototypeOf() 方法来替代 __proto__ getter 来确定一个对象的 [[Prototype]]。无论如何获取并改变一个对象的 [[Prototype]] 都是极为不推荐的,因为这样做是非常缓慢的,会使现代 JavaScript 引擎严重减速从而影响后续代码执行速度。但是,在 ES6 中提供了 Object.setPrototypeOf() 作为一种略微优先的方法来替代 __proto__ setter。

但是你现有的代码却可以运行,让我们看看原因。
  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' );
    

由于更改__proto__不被推荐,因此最好的方法是仅使用new关键字。

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

假设你只有一个叫做object1的对象,但是没有MyObject定义。那么,你可以像这样使用constructor属性:

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

4
thefourtheye提到,在对象创建后更改[[Prototype]]是强烈不建议的。
然而,在你的用例中,你并没有理由在对象的生命周期的随机点上更改[[Prototype]],而是想要创建一个具有给定[[Prototype]]的对象。
实现这一目标的方法是使用Object.create,该方法创建一个带有指定[[Prototype]]值的对象。
var object2 = Object.create(object1);
object1.constructor.call(object2, 'bar');

如果您所需的环境不支持Object.create,MDN页面上提供了一个shim。虽然不完美(并非所有功能都被覆盖),但在这种情况下,shim正好可以满足您的需求。

我一直在研究Object.create,但从MDN上的示例来看,它似乎只是用于复制对象定义而不是实例。我讨厌那个网站...我总是很难理解他们写的东西。感谢您提供的专业知识! - McShaman

3

4
作为一个过时的旧功能,是的。 - Bergi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接