注意:更改 的值被认为是一种不好的做法__proto__
。JavaScript 的创建者 Brendan Eich 等人强烈反对这样做。事实上,该__proto__
属性已从一些 JavaScript 引擎(如 Rhino)中完全删除。如果您想知道原因,请阅读Brendan Eich的以下评论。
更新:浏览器不会删除该__proto__
属性。事实上,ECMAScript Harmony现在已经标准化了__proto__
属性和setPrototypeOf
功能。__proto__
仅出于遗留原因支持该属性。强烈建议您使用setPrototypeOf
和getPrototypeOf
而不是__proto__
。
警告:虽然setPrototypeOf
现在是一个标准,但你仍然不鼓励使用它,因为改变对象的原型总是会杀死优化并使你的代码变慢。此外,使用 的setPrototypeOf
通常是低质量代码的指示。
您无需担心您现有的代码有一天无法工作。该__proto__
物业是在这里停留。
现在,对于手头的问题。我们希望以符合标准的方式做类似的事情:
var a = {
b: "ok"
};
a.__proto__ = {
a: "test"
};
alert(a.a); // alerts test
alert(a.b); // alerts ok
显然你不能Object.create
用来达到这个目的,因为我们不是在创建一个新对象。我们只是想改变[[proto]]
给定对象的内部属性。问题是[[proto]]
一旦创建对象就不可能更改其内部属性(除了__proto__
我们试图避免的使用方式)。
所以为了解决这个问题,我写了一个简单的函数(注意它适用于除函数之外的所有对象):
function setPrototypeOf(obj, proto) {
var result = Object.create(proto);
var names = Object.getOwnPropertyNames(obj);
var getProp = Object.getOwnPropertyDescriptor;
var setProp = Object.defineProperty;
var length = names.length;
var index = 0;
while (index < length) {
var name = names[index++];
setProp(result, name, getProp(obj, name));
}
return result;
}
因此,我们现在可以在创建后更改任何对象的原型,如下所示(请注意,我们实际上并没有更改[[proto]]
对象的内部属性,而是创建了一个与给定对象具有相同属性并从给定原型继承的新对象):
var a = {
b: "ok"
};
a = setPrototypeOf(a, {
a: "test"
});
alert(a.a); // alerts test
alert(a.b); // alerts ok
<script>
function setPrototypeOf(obj, proto) {
var result = Object.create(proto);
var names = Object.getOwnPropertyNames(obj);
var getProp = Object.getOwnPropertyDescriptor;
var setProp = Object.defineProperty;
var length = names.length;
var index = 0;
while (index < length) {
var name = names[index++];
setProp(result, name, getProp(obj, name));
}
return result;
}
</script>
简单高效(我们没有使用该__proto__
属性)。