__proto__,什么时候会消失?备择方案?

jdw*_*jdw 16 javascript prototype-programming

Mozilla声称它会在一段时间后删除__proto__(〜2008)并且它仍然在浏览器中.它仍然会被弃用吗?它适用于Opera,(我认为是Safari)和Chrome.我不需要担心IE,所以我很乐意继续使用它.

但是,我不希望我的代码有一天停止工作,所以问我的问题:

__proto__允许死简单继承:

a.__proto__ = {'a':'test'}
Run Code Online (Sandbox Code Playgroud)

无论如何,我能以符合标准的方式复制这个吗?我知道有功能继承,这很丑陋,而且它过于复杂,我只想创建一个原型链.只是想知道是否有任何巫师解决了这个问题.

谢谢

Aad*_*hah 25

注意:改变它的值被认为是一种不好的做法__proto__.强烈建议不要使用JavaScript的创建者Brendan Eich.事实上,该__proto__属性已完全从像Rhino这样的JavaScript引擎中删除.如果你想知道为什么然后阅读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
Run Code Online (Sandbox Code Playgroud)

显然,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;
}
Run Code Online (Sandbox Code Playgroud)

所以我们现在可以在创建它之后更改任何对象的原型(请注意,我们实际上并没有更改[[proto]]对象的内部属性,而是创建一个与给定对象具有相同属性并且从给定原型继承的新对象):

var a = {
    b: "ok"
};

a = setPrototypeOf(a, {
    a: "test"
});

alert(a.a); // alerts test
alert(a.b); // alerts ok
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

简单而有效(我们没有使用该__proto__属性).

  • @Chuck,`__ proto__`属性被认为是下一版JavaScript的标准,正如@cliffsofinsanity上面指出的那样.实现者建议不要使用它,因为它还不是标准.因此它可能不适用于所有JavaScript引擎.理解为什么不建议使用某个特征而不仅仅是批评人,这总是一个好主意.因为所有主流浏览器都支持它,所以在网络上使用`__proto__`属性是完全正常的.我没有看到使用它的任何警告,除非它在Rhino中不起作用.它与Windows无关. (7认同)
  • 根据标准组织和JS引擎实现者的明确建议,你实际上是在告诉人们编写损坏的代码.根据这样的错误,Windows API和内部组件变得如此混乱.如果你可以避免它,你真的不应该.我真的不认为你应该在没有任何警告的情况下推荐它.你和我都不是比规范或语言实现者更高的权威.记住:实际上并没有包含`__proto__`的JavaScript版本 - 它是一些实现碰巧暴露的内部细节. (2认同)

Chu*_*uck 7

我认为Mozilla想要提出的实际观点是它是非标准的,因此实现者完全可以将其删除.

更简洁的做原型链的方法是Object.create.a使用原型创建对象的等效代码{'a': 'test'}是:

a = Object.create({'a':'test'})
Run Code Online (Sandbox Code Playgroud)

如果您需要使用一个垫片,也可以在不支持它的浏览器中模仿此功能,这是直接搞乱的另一个优点__proto__.