4

回答(以下をお読みください。それぞれの著者が貴重な洞察を提供してくれました):

  • 「writable: false」は新しい値の割り当てを防ぎますが、 Object.defineProperty は割り当て操作ではないため、「writable」の値を無視します
  • プロパティ属性は継承されるため、1 つのサブクラス (またはサブクラスのインスタンス) が「書き込み可能」の値をそれ自体の true に戻すまで、プロパティはすべてのサブクラス/インスタンスで書き込み不可のままになります。

質問:

プロパティ「書き込み可能」記述子に関する MDN ドキュメントには、次のように記載されています。

書き込み可能 プロパティに関連付けられた値が代入演算子で変更できる場合にのみ true。デフォルトは false です。

公式の ECMA-262 第 6 版は多かれ少なかれ同じことを述べています。意味は明らかですが、私の理解では、元のプロパティ (つまり、その特定のオブジェクトのプロパティ) に限定されていました。

ただし、次の例 ( JSFiddle )を考慮してください。

//works as expected, overloading complete       
var Parent = function() {};
Object.defineProperty(Parent.prototype, "answer", {
    value: function() { return 42; }
});

var Child = function() {};
Child.prototype = Object.create(Parent.prototype, {
    answer: {
        value: function() { return 0; }
    }
});

var test1 = new Parent();
console.log(test1.answer()); //42
var test2 = new Child();
console.log(test2.answer()); //0

//does not work as expected
var Parent2 = function() {};
Object.defineProperty(Parent2.prototype, "answer", {
    value: function() { return 42; }
});

var Child2 = function() {};
Child2.prototype = Object.create(Parent2.prototype);

test3 = new Parent2();
console.log(test3.answer()); //42
test4 = new Child2();
test4.answer = function() { return 0; };
console.log(test4.answer()); //42

この例に従うと、プロパティは書き込み可能ではありませんが、予想どおり、サブクラス (test2) のプロトタイプでオーバーロードできることがわかります。

ただし、サブクラスのインスタンス (test4) でメソッドをオーバーロードしようとすると、暗黙のうちに失敗します。test2 と同じように動作することを期待していました。親のインスタンスでプロパティをオーバーロードしようとすると、同じことが起こります。

同じことが NodeJS と JSFiddle の両方で発生し、特定の条件下では、インスタンスでオーバーロードすると、プロパティの読み取り専用の性質に関する TypeError がスローされます。

これが予期された動作であることを確認していただけますか? もしそうなら、説明は何ですか?

4

3 に答える 3

3

はい、これは予期される動作です。

それは静かに失敗します。

ではない正確に。または: ずさんなモードでのみ。を"use strict"モードにすると、

Error { message: "Invalid assignment in strict mode", … }

ライン上test4.answer = function() { return 0; };

サブクラスのプロトタイプ (test2) ではオーバーロードできますが、サブクラスのインスタンス (test4) ではオーバーロードできません。

これは、インスタンスとプロトタイプとは関係ありません。気付かなかったのは、オーバーロード プロパティを作成するためにさまざまな方法を使用していることです。

  • 継承され、書き込み不可のプロパティへの代入は失敗します
  • Object.definePropertyオブジェクトが拡張不可能でない限り、呼び出しは新しいプロパティを作成するだけです

インスタンスに対しても同じことができます。

Object.defineProperty(test4, "answer", {
    value: function() { return 42; }
});
于 2016-02-03T15:01:11.580 に答える
3

そのプロトタイプがそのプロパティを書き込み不可として定義している場合 (およびオブジェクト インスタンスに記述子がない場合)、インスタンス プロパティに書き込むことはできません。子 (インスタンス) に書き込みます。EcmaScript-262セクション 9.1.9 1.ciを参照してください。

4. If ownDesc is undefined, then
  a. Let parent be O.[[GetPrototypeOf]]().
  b. ReturnIfAbrupt(parent).
  c. If parent is not null, then
      i. Return parent.[[Set]](P, V, Receiver).

ただし、それを回避しようとしている場合は、インスタンス自体の記述子を設定できます。

var proto = Object.defineProperties({}, {
  foo: {
    value: "a",
    writable: false,  // read-only
    configurable: true  // explained later
  }
});

var instance = Object.create(proto);
Object.defineProperty(instance, "foo", {writable: true});
instance.foo // "b"
于 2016-02-03T14:56:50.987 に答える
0

私はあなたのサンプルコードを取り、可能な結果を​​変更するすべての可能な方法を構造化しました: https://jsfiddle.net/s7wdmqdv/1/

var Parent = function() {};
Object.defineProperty(Parent.prototype,"type", {
    value: function() { return 'Parent'; }
});
var oParent = new Parent();
console.log('parent', oParent.type()); // Parent


var Child1 = function() {};
Child1.prototype = Object.create(Parent.prototype, {
    type: {
        value: function() { return 'Child1'; }
    }
});
var oChild1 = new Child1();
console.log('child1', oChild1.type()); // Child1


var Child2 = function() {};
Child2.prototype = Object.create(Parent.prototype);
Object.defineProperty(Child2.prototype, 'type', {
    value: function() { return 'Child2'; }
});
var oChild2 = new Child2();
console.log('child2', oChild2.type()); // Child2


var Child3 = function() {};
Child3.prototype = Object.create(Parent.prototype);
var oChild3 = new Child3();
oChild3.type = function() { return 'Child3'; };
console.log('child3', oChild3.type()); // Parent


var Child4 = function() {};
Child4.prototype = Object.create(Parent.prototype);
Child4.prototype.type = function() { return 'Child4'; };
var oChild4 = new Child4();
console.log('child4', oChild4.type()); // Parent


Object.defineProperty(Parent.prototype,"type", {
    value: function() { return 'Parent2'; }
});
var oParent2 = new Parent();
console.log('parent2',oParent2.type());

Object.create(...) を使用してプロトタイプを複製する場合、元の記述子は引き続きプロトタイプ チェーンの上位に接続されます。

それに何かを割り当てるときchild.answer = 10は、 を使用しますChild.prototype.answer.writable。それが存在しない場合は、存在するChild.prototype.constructor.prototype.answer.writableかどうかを試みます。

ただし、試してみるObject.defineProperty(Child.prototype, ...)と、プロトタイプチェーンはチェックされません。Child.prototype で定義されているかどうかをテストします。定義されていない場合は、定義されます。

于 2016-02-03T15:01:14.347 に答える