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

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

ただいまの
回答率

87.48%

オブジェクトの同じプロパティから何度も値を取得する場合について

解決済

回答 4

投稿

  • 評価
  • クリップ 0
  • VIEW 616

score 15

知りたいこと

APIを叩いて取得したJSONをもとに処理が実装されているコードで、該当のソースコード に記載したようなソースコードを仕事で見かけます。

□ オブジェクトの同じプロパティから何度も値を取得する場合
・変数に格納したほうが良い?
・変数に格納したほうが良い(悪い)場合の理由(速度が速いとか?)
・その他 メリット/デメリット が知りたいです。

該当のソースコード

const resultData = {
  a: {
    b: {
      c: {
        d: "データ"
      }
    }
  }
}

// ↓こうしたほうがいい?
// resultHogeHogeData = resultData.a.b.c.d;

if (typeof resultData.a.b.c.d === "string") {
  if (resultData.a.b.c.d.length === 0) {

  } else if (resultData.a.b.c.d.length === 1) {

  }
} else if (typeof resultData.a.b.c.d === "boolean") {

} else if (typeof resultData.a.b.c.d === "function") {

} else {

}

// その後の処理でもなんだかんだ使ったり

自身では
変数に格納せずそのままアクセスして値を取得したほうが、どのプロパティから値を取得しているかがわかりやすい。
(変数に入れると変数名ではオブジェクトのどの階層のプロパティにアクセスしているかまで一見してわからない)
でも、こういうのは変数に格納するっていう先入観があるからなぁ・・・と悩ましい状態です。

素朴な疑問で申し訳ありませんが、どなたかご存じの方がおられましたらご教示頂けますと幸いです。
よろしくお願い致します。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 4

checkベストアンサー

+2

10年前の古いデータですが、、(ハイパフォーマンスJavascipt(オライリー)より)
イメージ説明
リテラルやローカル変数に比べて、オブジェクトメンバへのアクセスは、多少コストがかかる傾向にはあるのは確かですが、まぁ誤差ですね。

resultData変数の定義場所と利用箇所が同じ関数ローカルなら、オブジェクトのネストが深くても、ローカル変数に持ち直す事のパフォーマンス的なメリットはあまりないと思います。

ただ長くなりすぎると、コードが横に伸びて読みにくいので、可読性的な意味で持ち直す事は、個人的にはわりとやります。

ただし、関数外に定義した変数を読む場合、関数スコープを手繰って行くコストがかかる場合があるため、
オブジェクトのネストは関係なく、ローカルに持ち直すことはパフォーマンス的に有利になります。

a = 1

function func1() {

    var b = 2
    var c = 3

    function func2() {
        var e = 4

        alert(a)
    }
}

このfunc2を呼び出す際、利用している変数「a」を探すため、

  1. func2 のローカルスコープ内を探す
  2. func1 のスコープ内を探す
  3. グローバルスコープ内を探す

という形で走査して変数を探すことになるため、ローカルに定義された変数へのアクセスが、最もコストが安い事になります。
なので、例えばグローバルに定義されているdocumentオブジェクト等をループで何度も参照するような場合など、あえてローカルに持ち直したりします。

頻繁につかうスコープ外の変数をローカルに持ち直すのは、パフォーマンス的に有利です。

function func1() {

    function func2() {
        var doc = document; // グローバルなdocumentをローカルに持ち直す。

        for(var i=0; i<100000; i++) {
            var tmp = doc.getElementById("id_" + i).value;
        }
    }
}


※ブラウザの実装によって最適化されていたりもします。なので効果は必要に応じて対象ブラウザで計測すべきことなので、あくまで一般論としてとらえて下さい。

示されているソースの例の場合、オブジェクトのネストを気にするよりも、
if文を何度も書かずにswitch文を使えば、キレイになる気がします。

switch(typeof(resultData.a.a.b.c.d)){
    case "string": 
        ...
    case "boolean":
        ...
    default:

}

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2021/01/14 18:28

    umau さん
    ご回答ありがとうございます。
    > resultData変数の定義場所と利用箇所が同じ関数ローカルなら、オブジェクトのネストが深くても、ローカル変数に持ち直す事のパフォーマンス的なメリットはあまりないと思います。
    そうねんですね!
    これはかなり気になっていたので教えて頂けてとてもありがたいです。

    > 長くなりすぎると、コードが横に伸びて
    やっぱりそうですよね、私もこれはとても感じていて「resultData.hogehoge.fugafugafuga.xxxxxxxx」みたいなものを何回も書くのはどうかと思ったりすることが多々あります。

    > 関数外に定義した変数を読む場合、関数スコープを手繰って行くコストがかかる場合があるため、オブジェクトのネストは関係なく、ローカルに持ち直すことはパフォーマンス的に有利になります。
    なるほど、スコープを手繰るところは全然意識できていませんでした。
    ローカルに持つ(持ち直す)というのはこういう意味でも重要なんですね。とても参考になりました、ありがとうございます!

    キャンセル

+2

オブジェクトの同じプロパティから何度も値を取得する場合

本当に「何度も値を取得したい」のでしょうか?それとも、「値を得るのは1回でいいから、その値を何度も使いたい」のでしょうか?

JavaScriptではあまり例は多くないですが(この例とも関係ありません)、プロパティ参照自体も1つの演算ですので、やるたびに結果が異なることがありえます。いったん変数に確保したほうが、「同じ値について処理を行っている」ことがはっきりします。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2021/01/14 18:27

    maisumakun さん
    ご回答ありがとうございます。
    > 「値を得るのは1回でいいから、その値を何度も使いたい」のでしょうか?
    説明不足で申し訳ありません。
    そのケースが殆どです。
    if 文などで比較されるオブジェクトの値は変わることは基本的にないですが、その結果によって他のプロパティの値を書き換えたりして別サーバーに返却することがあります。

    > やるたびに結果が異なることがありえます。いったん変数に確保したほうが、「同じ値について処理を行っている」ことがはっきりします。
    これはとても参考になりました。
    同じオブジェクトでもどういった値なのかわかりやすくするために、変数に格納したほうが良いケースがあることを意識したいと思います。ありがとうございます。

    キャンセル

+1

基本的に再代入して新しい名前を付けたほうがよいでしょう。このような名前を説明変数と呼びます。なんども同じ概念を使い回すのならば別の名前を与えたほうが認知負荷が低いのです。それにもし resultData.a.b.c.d.length じゃなくて resultData.a.b.c.e.length に変更だー!ってなったら大変ではありませんか?ですので一旦変数に格納したほうがよいでしょう。

ただし例外があります。それは特殊な働きにより result.a とアクセスするたびに結果が変わるやつです。この場合は毎回その名前でアクセスしなければいけません。ドキュメントに書いてあるはずなのでよく読みましょう(書いてなかったりするんだよな〜)。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2021/01/14 18:26

    A_kirisaki さん
    ご回答ありがとうございます。
    > resultData.a.b.c.d.length じゃなくて resultData.a.b.c.e.length に変更だー!ってなったら大変ではありませんか?
    そうですよね、私もプログラムを学び始めた頃によくそう教えられてきましたので、先入観の一つとして「変数に格納する」というものがありましたのでほっと出来ました。

    > ただし例外があります。それは特殊な働きにより result.a とアクセスするたびに結果が変わるやつです。
    他の方もおっしゃられているように、やはりここを意識しないとダメなんですね。私の意識化では欠けていましたので今後気をつけるように心がけたいと思います。ありがとうございます。

    キャンセル

+1

総じて要件によるです。

変数に入れると変数名ではオブジェクトのどの階層のプロパティにアクセスしているかまで一見してわからない

に関しては、必要なパターンもあれば、
必要ないパターンもありますので、やはり要件によります。
例えば、該当のオブジェクトを、
そのプログラム内では該当の値のみしか使わないなんて時は、
オブジェクト階層を識別する必要はありません。

ただし、オブジェクトの、他の階層の値を複合して使う必要がある、など、
その多階層に渡って、値が必要になる場合は、
階層を識別できる状態にしておいた方が、いいでしょう。

・変数に格納したほうが良い?

上記の通りです。

・変数に格納したほうが良い(悪い)場合の理由(速度が速いとか?)

特に変わらないパターンの方が多いです。
ただし、変数生成を、何万個とかする場合、循環参照など、メモリから解放できないような構文(メモリリーク)になっていた場合は、高確率で速度に影響します。
それ以外は、運用面上、要件上でどちらがいいか、でいいと思います。

・その他 メリット/デメリット が知りたいです。

上記の中で、回答になっているとは思います。
ただ、メリット・デメリットよりは、要件によって適した構文を組むことを意識するのが、エンジニアとして大事かと思います。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2021/01/14 18:27

    miyabi_takatsuk さん
    ご回答ありがとうございます。
    > そのプログラム内では該当の値のみしか使わないなんて時は、オブジェクト階層を識別する必要はありません。
    > その多階層に渡って、値が必要になる場合は、階層を識別できる状態にしておいた方が、いいでしょう。
    確かにそうですよね!説明不足で後付になってしまいますが、私が直面しているケースでは、「多階層に渡って~」が多いので、識別できる状態(= 変数に格納せずそのまま参照)のほうが可読性も良い気がします。

    > ただし、変数生成を、何万個とかする場合、循環参照など、メモリから解放できないような構文(メモリリーク)になっていた場合は、高確率で速度に影響します。
    > それ以外は、運用面上、要件上でどちらがいいか、でいいと思います。
    承知致しました。
    変数に格納するにしても何万個も変数を生成するようなことは私の状況下ではなさそうですが、多階層に渡って値が必要になる場合は多々ありますので、多階層に渡る場合やそうではない場合も考慮しつつ、運用面、要件を意識してみます。
    とても参考になりました!ありがとうございます。

    キャンセル

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

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

関連した質問

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