Mozilla声称它会在一段时间前(~2008(删除__proto__,并且它仍在浏览器中。它仍然会被弃用吗?它适用于Opera(我认为是Safari(和Chrome。我不需要担心IE,所以我很想继续使用它。
但是,我不希望我的代码有一天停止工作,所以关于我的问题:
__proto__允许死的简单继承:
a.__proto__ = {'a':'test'}
无论如何,我可以以符合标准的方式复制它吗?我知道有函数继承,这很丑陋,它使我只想创建一个原型链的事实过于复杂。只是想知道是否有任何巫师已经解决了这个问题。
谢谢
注意:更改 __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__
属性(。
我认为Mozilla想要表达的实际观点是它是非标准的,因此实现者完全可以在他们的权利范围内删除它。
制作原型链的更清洁方法是 Object.create
.使用原型{'a': 'test'}
创建对象a
的代码的等效项是:
a = Object.create({'a':'test'})
如果您需要使用一个垫片,也可以在不支持它的浏览器中模仿此功能,这是直接弄乱__proto__
的另一个优势。
我不明白如何:
var a = {};
a.__proto__ = A; // A is object because no constructor is needed
比以下方法简单:
var a = new A(); // A is Constructor function
现在,如果您不需要构造函数,则在后一种情况下设置 A 可能会更冗长,但是在这种情况下,您可以将其自动化为同样简单:
var A = Constructor({
method: function(){}
}); // A is function, meant to be used with new
与以下相比:
var A = {
method: function(){}
}; //A is object, meant to be set as __proto__
如果你需要一些初始化逻辑,它最终可能会更容易使用。无论如何都需要声明构造函数的正常方式