16

Mozilla は、しばらく前 (~2008 年) __proto__ を削除すると主張しましたが、まだブラウザーに残っています。それはまだ廃止される予定ですか?Opera、(Safariだと思います)、Chromeでも動作します。IEは気にしなくていいので、これからも使いたいです。

ただし、コードがいつか機能しなくなることを望んでいないので、質問に進みます。

__proto__ は単純な継承を可能にします:

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

これを標準に準拠した方法で複製できる方法はありますか? 関数の継承があることは知っていますが、それは醜く、プロトタイプ チェーンを作成したいだけという事実を非常に複雑にしています。ウィザードがこれを解決したかどうか疑問に思っています。

ありがとう

4

3 に答える 3

27

注:の値を変更することは悪い習慣と考えられています__proto__。そうすることは、特に JavaScript の作成者である Brendan Eich によって強く推奨されていません。実際、この__proto__プロパティは、Rhino などのいくつかの JavaScript エンジンから完全に削除されています。その理由を知りたい場合は、Brendan Eich による次のコメントをお読みください。

更新:__proto__ブラウザーはプロパティを削除しません。実際、ECMAScript Harmony__proto__はプロパティとsetPrototypeOf関数の両方を標準化しています。プロパティは、__proto__従来の理由でのみサポートされています。の代わりにsetPrototypeOfandを使用することを強くお勧めします。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__回避しようとしている using による場合を除きます)。

この問題を解決するために、単純な関数を作成しました (関数を除くすべてのオブジェクトで機能することに注意してください)。

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__シンプルで効率的です (このプロパティは使用しませんでした)。

于 2012-05-07T05:46:00.443 に答える
7

Mozilla が伝えたかった実際のポイントは、それが非標準であるため、実装者はそれを完全に削除できるということだと思います。

プロトタイプ チェーンを行うためのよりクリーンな方法は、 ですObject.createaプロトタイプを使用してオブジェクトを作成するためのコードは、次の{'a': 'test'}とおりです。

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

サポートしていないブラウザでこの機能を模倣するシムもあります。これは、直接いじるよりも別の利点__proto__です。

于 2012-05-07T04:39:00.957 に答える
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__

また、初期化ロジックが必要な場合は、コンストラクター関数を宣言する必要がある通常の方法を使用する方が簡単になるでしょう。

于 2012-05-07T04:25:46.080 に答える