最終行
前置きが長くなります。
ご質問はリンク先の「性能」のセクションです。
性能として、考えるべき要点が次の2点で、トレードオフにあることを考える必要があります。
- プロパティの検索時間
- メモリ効率
「2値を加減算する」機能を持ったオブジェクトを異なる方法で定義してみます。
- メンバ関数をコンストラクタ関数内で定義する方法
- メンバ関数をコンストラクタ関数の prototype で定義する方法
javascript
1// 1.
2function MyClass(...args){
3 if( args[0] instanceof MyClass ) return args[0]
4
5 this.a = args[0];
6 this.b = args[1];
7
8 this.sum = function(){
9 return this.a + this.b;
10 }
11 this.sub = function(){
12 return this.a - this.b;
13 }
14}
15// 2.
16function MyClass(a, b) {
17 this.a = a;
18 this.b = b;
19}
20MyClass.prototype = {
21 sum : function(){
22 return this.a + this.b;
23 },
24 sub : function(){
25 return this.a - this.b;
26 }
27}
この2つの定義方法、インスタンスは共に同じ機能を提供します。
javascript
1var c = new MyClass( 3, 2 );
2console.log( c.sum() ); // 5
3console.log( c.sub() ); // 1
しかし、内部では決定的に異なる実装です。
javascript
1// 1.
2console.log( c ); // MyClass {a: 3, b: 2, sum: ƒ, sub: ƒ}
3console.log( c.__proto__ ); // {constructor: ƒ}
4
5// 2.
6console.log( c ); // MyClass {a: 3, b: 2}
7console.log( c.__proto__ ); // {sum: ƒ, sub: ƒ, constructor: ƒ}
トレードオフにある2つを考えると、次のようなことが言えます
- はインスタンスごとに sum(), sub() を直接持つ分、メソッド検索は高速だがメモリを食う。
- はインスタンスごとに sum(), sub() を[[Prototype]]参照する分、列挙に時間を要するが、メモリを節約できる。
現在の実行環境では、Canvasへの膨大な書き換えなどで起こる程度と、その速度差は小さくなっています。
なので、可読性も高い 2. の方法が使われます。
最終行
回答です。
for..in
のような列挙は、[[Prototype]]
に定義されたメンバを順次参照することを述べていて、プロパティサーチが幾重にも重なると、所要時間が性能面に関わることを説明しています。
ですので、長い前置きの通り、トレードオフとなる特徴から、しっかり選ぶ必要があるということです。
※MDN上級者向けのページは、コードを書いた経験、読んだ経験を積んで読み直すと、理解が変わります。
追記)
まさか, Bがaを持っている場合に, Cのプロパティも列挙されるわけではないですよね?
MDNに
加えて、存在しないプロパティへのアクセスは、常にプロトタイプチェーン全体を通過します。
と条件を示している通り、プロパティが見つかった時点でサーチは終了します。
(これが、ご質問の本質であり、求める回答でしょうか?)
継承を行った時は、この特徴が関連してきます。
- オブジェクトAの定義
class A {}
A[[Prototype]].method
- Aから派生したオブジェクトBの定義
class B extends A {}
B[[Prototype]].method
AにもBにも同じ名称のmethodがある場合、B のインスタンス bでは、親Aの持つ同名のmethodを参照しません。
Bのmethodで参照する必要がある場合、
- 古典的実装
javascript
1B.prototype.method = function() {
2 // A.prototype に定義されたメンバと明示して、call()/apply()で利用
3 return A.prototype.method.call(this) * 10
4}
2.Classブロック(シンタックスシュガー)
javascript
1class B extends A {
2 /* omitted */
3 method () {
4 // 親を参照するための インタックスシュガー super が使える。
5 return super.method() * 10
6 }
7}
質問では「とあるオブジェクト」のような身勝手な想像上の表現では分かりづらいです。
リファレンスにも記述される様式 で具体的な定義を示したり、箇条書きにすると、回答もしやすい。
また、インスタンスもオブジェクトに違いないのですが、区別したほうが伝わりやすいです。
- オブジェクト=抽象化の定義
- インスタンス=具象化したオブジェクト
とにかく、少しでも理解が深まれば幸いです。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/12/25 09:09