質問: { length: 0, addElem: function addElem (elem) { // obj.length は、要素が追加されるたびに自動的に増分する。 Array.prototype.push.call(this, elem); } }; // 例示のために空のオブジェクトを追加する。 obj.addElem({}); obj.addElem({}); obj.addElem({}); console.log(obj.length); // → 3 console.log(obj); // → {0: {...}, 1: {...}, 2: {...}, length: 3, addElem: f} console.log('--------------------------'); let obj_1={ length : 0 } obj_1.prop_1='prop_1'; console.log(obj_1.length); // 0 console.log(obj_1); // {length: 0, prop_1: "prop_1"} ``` mdnのサンプルなんですが、まず前回の質問と同じで、addElemの中で Array.prototype.push.call(this, elem); としているのですが、これで addElemを実行する度にobjにプロパティが追加されるのがなぜなのか? なぜthisをobjに固定すると、オブジェクトであるobjにプロパティを追加できるのか? と思ってしまうのですが、これは、pushがそういう風に作られているから、と理解しておくのが良いでしょうか? というか、オブジェクトに対してArray.prototype.pushを使用する方法が上記の方法だ、という理解で問題ないでしょうか? 次に上記のサンプルの前半(----------------)よりも上の部分。でaddElemを実行する度にlengthプロパティが増えていくのですが、これは何の働きでこうなるのでしょうか。 objのlengthプロパティは組み込みで最初から用意されているのではなく、プログラマが勝手に用意したプロパティだと思うのですが、上記のコードだけで当然のようにlengthが増えているのがかなり不自然に思えます。 試しに上記サンプルの後半のように、自分でlengthプロパティを持ったオブジェクトobj_1を作って、obj_1に対してプロパティprop_1を追加してもlengthプロパティは0のままです。 あと上記mdnのページの中で > > push はジェネリックメソッドとして用意されています。そのため call() や apply() と一緒にオブジェクトに対して利用することもできます。 > > > と説明があるのですが、ジェネリックメソッドとは何ですか?
回答: まず、 `Array.prototype.push()`の使い方として一般的には以下のように使います。 ``` var arr = []; arr.push(1); arr.push(2); console.log(arr) // [1, 2] ``` `Array.prototype.push()`メソッドは内部で`this` に対して要素を追加するという処理をしています。 また関数オブジェクトが持つ `.call()` メソッドは関数を実行する際の`this` を指定できます。 その為、`Array.prototype.push.call()`メソッドで `this` にオブジェクトを指定すると、そのオブジェクトに対して要素が追加されるという動作になります。 このようなメソッドの処理の対象を引数で指定できるメソッドをジェネリックメソッドと呼んでいます。 `.push()`メソッドでは配列風のオブジェクトに対して要素を追加することができるので、Object等を`this`に指定しても概ね動作するのですが、基本的にはArrayオブジェクトの為のメソッドであり、Arrayオブジェクトが持つ配列長を格納する`length`プロパティに対して値を増分する処理を行います。プロパティがなければ作成されます。 もう少し補足しますと、`.push()`メソッドの実行時、まず`length`プロパティを参照し、その値をキーとして要素を追加します。`length`プロパティがない場合のキーは `0`です。その為以下のような動きになります。 ``` obj = { 0: 'foo', length: 1 } Array.prototype.push.call(obj, 'bar'); console.log(obj); // {0: "foo", 1: "bar", length: 2} ``` 個人的にはArrayオブジェクト以外で `Array.prototype.push()` は使わない方が良いと思います。