ジョン・レシグは間違っている
はい、jQuery の作成者も間違いを犯す可能性があります。これは彼が述べたことです:
constructor
JavaScript の各オブジェクトには、オブジェクトの作成に使用されたコンストラクターを参照するという名前の暗黙的なプロパティがあります。また、プロトタイプはコンストラクターのプロパティであるため、各オブジェクトにはプロトタイプを見つける方法があります。
彼の発言が誤りである理由は次のとおりです。
- すべてのオブジェクトにプロトタイプがあるわけではありません。したがって、これらのオブジェクトには暗黙的なプロパティもありません。
- プロトタイプを持つすべてのオブジェクトがコンストラクター関数によって作成されるわけではありません。ただし、これらのオブジェクトはコンストラクター関数によって暗黙的に作成されるため、これにはオブジェクト、配列、および正規表現のリテラルと関数は含まれません。
- プロトタイプを持ち、コンストラクター関数によって作成されるすべてのオブジェクトに、 という名前の暗黙のプロパティがあるわけではありません
constructor
。
- プロトタイプを持ち、コンストラクターによって作成され、名前付きの暗黙的なプロパティを持つすべてのオブジェクトが、
constructor
そのオブジェクトを作成したコンストラクター関数を指すプロパティを持っているわけではありません。
constructor
プロトタイプを持ち、コンストラクターによって作成され、そのオブジェクトを作成したコンストラクター関数を指すという名前の暗黙的なプロパティを持ち、prototype
そのコンストラクター関数で呼び出されるプロパティを持つすべてのオブジェクトがあるわけではありません。
constructor
プロトタイプを持ち、コンストラクターによって作成され、そのオブジェクトを作成したコンストラクター関数を指すという名前の暗黙的なプロパティを持ち、prototype
そのコンストラクター関数で呼び出されるプロパティを持ち、そのプロパティがそのオブジェクトのプロトタイプを指すわけではありません。
これらのステートメントを例で証明して、John Resig のステートメントが誤りであることを証明しましょう。これらのステートメントはすべて「すべてのオブジェクトではない」という主張で始まっているため、John Resig のステートメントが誤りであることを証明するには、各ステートメントの 1 つの例を見つけるだけで済みます。
ステートメント 1 の証明
このObject.create
メソッドを使用して、新しいオブジェクトを作成し、その内部[[prototype]]
プロパティを設定できます。したがって、プロトタイプを持たないオブジェクトを作成するために使用できます。
var o = Object.create(null); // o has no prototype
上記の例のオブジェクトにはプロトタイプがなく、内部[[prototype]]
プロパティが に設定されていnull
ます。したがって、暗黙的なプロパティもありません。
ステートメント 2 の証明
次のようにp
、オブジェクトから継承する別のオブジェクトを作成しましょう。o
var p = Object.create(o); // the prototype of p is o
したがって、オブジェクトp
にはプロトタイプがありますが、コンストラクターによって作成されたものではありません。
ステートメント 3 の証明
よし、代わりにコンストラクターからオブジェクトを作成しましょうp
(実際、これはまさにObject.create
関数の実装方法です)。
function F() {} // F is a constructor
F.prototype = o; // objects constructed by F inherit from o
var p = new F; // p is an object which is constructed by F
ここで、オブジェクトp
はコンストラクターによって作成されF
ます。ただし、という名前の暗黙的なプロパティはありませんconstructor
。
ステートメント 4 の証明
変数o
にオブジェクト リテラルが割り当てられ、prototype
コンストラクターのプロパティとして使用された場合はどうなるF
でしょうか。
var o = {}; // object literals inherit from Object.prototype
function F() {} // F is a constructor
F.prototype = o; // objects constructed by F inherit from o
var p = new F; // p is an object which is constructed by F
これで、オブジェクトp
には という名前の暗黙のプロパティがありますが、それはではなく をconstructor
指しています。したがって、の代わりに を指します。Object
F
p.constructor.prototype
Object.prototype
o
陳述書の証明 5
おそらく問題は継承だと思いますか?よし、継承を完全にやめましょう。ゼロから始める:
var p = new F; // p is constructed by F, it inherits from F.prototype
delete F.prototype; // devious isn't it? I love being naughty
function F() {} // declarations are hoisted
これで、オブジェクトp
は から継承され、それ自体を指すF.prototype
という名前の暗黙のプロパティがあります。ただし、 からプロパティを削除したため、 viaのプロトタイプにアクセスできません(現在は が返されます)。constructor
F
prototype
F
p
p.constructor.prototype
undefined
陳述の証明 6
最後の例を少し変更してみましょう。削除する代わりに、別のF.prototype
ものに設定します。例えば:
var o = {}; // object literals inherit from Object.prototype
var p = new F; // p is constructed by F, it inherits from F.prototype
F.prototype = o; // oops, what will happen now?
function F() {} // declarations are hoisted
オブジェクトp
は から継承し、それ自体を指すF.prototype
という名前の暗黙のプロパティを持ちます。ただし、アクセス時にに設定しているため、元の の代わりに取得します。constructor
F
F.prototype
o
p.constructor.prototype
o
F.prototype
結論
ご覧のとおり、John Resig の発言は完全に誤りです。これを証明するのに 6 つの例は必要ありませんでした。どれか1つの例で十分です。しかし、私は彼の発言がどれほど間違っているかを示したかった. したがって、私は彼の発言を反証する考えられるすべての例を書きました。
JavaScript はプロトタイプのオブジェクト指向プログラミング言語であり、オブジェクトが他のオブジェクトから継承されることを意味します。コンストラクターは、オブジェクトを作成するために厳密に必要というわけではありません。ただし、残念ながらそれが JavaScript でプロトタイプの継承が機能する方法であるため、それらは過度に重要視されています。
プロトタイプ継承のコンストラクター パターンは、しばしば混乱を招き、誤解を招きます。さらに、コンストラクターを使用しないプロトタイプ継承の真の方法 (プロトタイプ継承のプロトタイプ パターン) を隠します。詳細については、次の回答をお読みください: https://stackoverflow.com/a/17008403/783743