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

What has replaced the deprecated __proto__ in JavaScript

本文关键字:proto 取代 JavaScript 是什么      更新时间:2023-09-26

我正在尝试弄清楚如何在不使用 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__属性,我将如何做到这一点呢?

引用

__proto__的MDN文档,

__proto__属性已弃用,不应使用。 应该使用Object.getPrototypeOf而不是__proto__ getter来确定对象的[[原型]]。 强烈不鼓励改变对象的[[原型]],无论如何完成,因为它非常慢,并且不可避免地会减慢现代JavaScript实现中的后续执行速度。 但是,ES6 中提供了Object.setPrototypeOf作为__proto__二传手的非常偏爱的替代品。

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

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

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

由于不建议更改__proto__,因此最好的方法是仅使用new关键字

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

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

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

正如thefoureye所提到的,在创建对象后更改对象的[[原型]]是非常不鼓励的。

但是,在您的用例中,您实际上没有理由在对象生命周期中的某个随机点更改 [[原型]],而是希望使用给定的 [[Prototype]] 创建一个对象。

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

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

如果你想要的环境不支持 Object.create,MDN 页面上有一个填充程序。虽然不完美(未涵盖所有功能),但填充程序正是在这种情况下所需的。

看起来 ECMAScript 6 的最新草案已经标准化__proto__。见 https://people.mozilla.org/~jorendorff/es6-draft.html B.2.2.1节。