我试图找出如何在不使用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__属性我该如何做呢?
答案 0 :(得分:7)
不推荐使用
__proto__
属性,不应使用该属性。应使用Object.getPrototypeOf
代替__proto__
getter来确定对象的[[Prototype]]。强烈建议不要改变对象的[[Prototype]],无论如何实现,因为它非常慢并且不可避免地减慢了现代JavaScript实现中后续执行的速度。但是,Object.setPrototypeOf
在ES6中作为__proto__
setter的一个非常优选的替代方案提供。
但是你的实际代码是有效的,让我们看看为什么。
首先,使用Object文字创建的任何对象都将__proto__
属性与Object.prototype
相同。您可以像这样检查
var object2 = {};
console.log(object2.__proto__ === Object.prototype);
# true
由于使用object1
函数创建MyObject
,因此以下情况属实
console.log(object1.__proto__ === MyObject.prototype);
# true
当你说
时object2.__proto__ = object1.__proto__;
从2开始,我们可以看到它与
相同object2.__proto__ = MyObject.prototype;
所以,您只是让JavaScript相信,object2
也是MyObject
的对象。
由于我们已将MyObject
的原型分配给object1
原型,因此两个对象的constructor
相同
console.log(object1.constructor === object2.constructor);
然后您使用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');
答案 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节。