__proto__ = null をした後の __proto__ = {} について
記事とは関係ない質問なのですが
__proto__にnullを設定した場合のみ
以降のinstanceof演算子の挙動が変わるのは仕様なのでしょうか
FirefoxとChromeで確認しましたo = {} o.__proto__ = Object.prototype o instanceof Object //true o.__proto__ = {} o.__proto__ = Object.prototype o instanceof Object //true o.__proto__ = 'abc' o.__proto__ = Object.prototype o instanceof Object //true o.__proto__ = undefined o.__proto__ = Object.prototype o instanceof Object //true o.__proto__ = null o.__proto__ = Object.prototype o instanceof Object //false o.__proto__ = {} o.__proto__ = Object.prototype o instanceof Object //falsehttp://d.hatena.ne.jp/teramako/20130713/p2#c1374302690
ちょっと面白い質問を受けました。
__proto__ の仕様
ECMAScript 6th から __proto__ が付録として仕様が定義されています。
Annex B.2.2.1 あたりに定義されていますが、Object.prototype.__proto__ として存在します。
大抵のオブジェクトが Object.ptototype をプロトタイプチェーンに持つため、obj.__proto__ で値を得たり代入したりができるという仕組みです。
大事なことなので二回言いますが、"__proto__" は Object.prototype にあります。
逆にいうと、プロトタイプチェーンに Object.prototype を持たないオブジェクトは、"__proto__" という特殊なプロパティを持たないことになります。
instanceof 演算子
instanceof 演算子は、左辺の[[Prototype]]と右辺のprototypeプロパティが一致するかを比べる演算子です。
Object.getPrototypeOf(o) === Constructor.prototype
と同様の結果を返すことになります。
問題のコード
o = {} o.__proto__ = Object.prototype o instanceof Object //true
まぁ、ここはいいでしょう。
o.__proto__ = 'abc' o.__proto__ = Object.prototype o instanceof Object //true o.__proto__ = undefined o.__proto__ = Object.prototype o instanceof Object //true
代入する'abc'
やundefined
は、Object または null ではないので、無効です。[[Prototype]] は変更されません。
o.__proto__ = null o.__proto__ = Object.prototype o instanceof Object //false
ここが問題です。
null を代入すると、[[Prototype]] が null に設定されます。これはプロトタイプチェーンに Object.prototype を持たないということを意味します。
そして、instanceof は null === Object.prototype
としたような状態となり、false となります。
o.__proto__ = {} o.__proto__ = Object.prototype o instanceof Object //false
さて、前のコードで、変数oの[[Prototype]]は null になっています。Object.prototype.__proto__へは結びつかない状態です。
この状態の __proto__ は普通のプロパティであり、特殊なものではなくなっています。
つまり、o.prop = {}
とした時と同じ扱いです。o.__proto__ = {}
は[[Prototype]]への設定ではなく、oの"__proto__"プロパティへ値の設置として働きます。
[[Prototype]]は変更されませんので、instanceof 演算も false を返すままということになります。
ということで、仕様通りです。