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

时间:2012-05-07 04:14:22

标签: javascript prototype-programming

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

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

__ proto__允许死简单继承:

a.__proto__ = {'a':'test'}

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

由于

3 个答案:

答案 0 :(得分:24)

注意:更改__proto__的值是一种不好的做法。强烈建议不要使用JavaScript的创建者Brendan Eich。事实上,__proto__属性已经完全从像Rhino这样的JavaScript引擎中删除了。如果你想知道为什么然后阅读Brendan Eich的following comment

更新:浏览器不会删除__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__属性)。

答案 1 :(得分:7)

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

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

a = Object.create({'a':'test'})

在不支持它的浏览器中也有模拟此功能的垫片,如果你需要使用它,这是直接使用__proto__的另一个优点。

答案 2 :(得分:1)

我不明白:

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__

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