質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.77%

javascriptのArray.prototype.pushをオブジェクトに使った時のlengthプロパティについて

解決済

回答 1

投稿

  • 評価
  • クリップ 2
  • VIEW 769

moriman

score 95

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/push

let obj = {
    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() と一緒にオブジェクトに対して利用することもできます。

と説明があるのですが、ジェネリックメソッドとは何ですか?

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+2

まず、 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() は使わない方が良いと思います。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/10/03 11:11 編集

    横やりすみません。
    > 個人的にはArrayオブジェクト以外で Array.prototype.push() は使わない方が良いと思います。
    これ禿同ですね。
    他言語でいう連想配列調オブジェクトはあくまでその型で扱いその中で処理するのが妥当だと私も思います。そのためかわからないですが、Object.keysやObject.entriesがありますしね。
    JSって型厳密じゃないから、拡張しないでこういうことできちゃうけど、
    他の言語じゃ通じないですしね。

    キャンセル

  • 2019/10/04 10:30

    解答を頂きましてありがとうございました。よくわかりました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.77%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る