注意:更改__proto__
. JavaScript 的创建者 Brendan Eich 等人强烈反对这样做。事实上,该__proto__
属性已从一些 JavaScript 引擎(如 Rhino)中完全删除。如果您想知道原因,请阅读 Brendan Eich 的以下评论。
更新:浏览器不会删除该__proto__
属性。事实上,ECMAScript Harmony现在已经标准化了__proto__
属性和setPrototypeOf
函数。__proto__
仅出于遗留原因支持该属性。强烈建议您使用setPrototypeOf
andgetPrototypeOf
而不是__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__
属性)。