__proto__,什么时候会消失?选择

__proto__, when will it be gone? Alternatives?

本文关键字:选择 消失 什么时候 proto      更新时间:2023-09-26

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__ 属性。强烈建议您使用 setPrototypeOfgetPrototypeOf 而不是 __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__

如果你需要一些初始化逻辑,它最终可能会更容易使用。无论如何都需要声明构造函数的正常方式