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

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

ただいまの
回答率

90.84%

  • JavaScript

    14778questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • Node.js

    1678questions

    Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

  • ESLint

    19questions

    ESLintは、JavaScriptのための構文チェックツール。全検証ルールを自由に on/offでき、独自のプロジェクトに合わせたカスタムルールを容易に設定することが可能。公開されている様々なプラグインを組み込んで使用することもできます。

JavaScriptのconstについて

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 565
退会済みユーザー

退会済みユーザー

    let obj = { id: 3 };
    obj.id = 4; //変更を加える


上記のコードですと、ESLintに「objは再代入されてないんだからconst使え!」と、
「prefer-const」にESLintのチェックに引っかかります。

JavaScriptのconstは他の言語とちょっと意味合いが違うのかもしれませんが、
上記のようなケースにおいて、JS使いの方はconst使いますか? 使った方が適切ですか?

補足

    let scale = d3.scaleLinear();
    console.log(scale.domain()); // ▶︎(2) [0, 1]
    scale.domain([0, 100]); //変更を加える
    console.log(scale.domain()); // ▶︎(2) [0, 100]


同じく、こういうのも「const使え!」とESLintに言われます。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 3

checkベストアンサー

+8

const は「変数の再代入を避ける」為に使います。
一方、質問者さんは「プロパティの再代入を避けられないこと」を考慮されていますが、これは別の問題です。

  • 「変数の再代入を避ける」為に const を使う
  • 「プロパティの再代入を避ける」為に Object.freeze() を使う

個別のプロパティ再代入を制御する場合は Object.create()Object.defineProperty() を使います。

Re: hayatomo さん 

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/09/10 12:36

    ```
    const obj = {id: 3};
    // obj.id = 5;
    ```
    再代入は以降されないことをconstにより明示。ただし、オブジェクト内の値が変わるかどうかについては不明。
    ```
    const obj = {id: 3};
    Object.freeze(obj);
    // obj.id = 5; //エラー
    ```
    再代入は以降されないことをconstにより明示。かつ、Object.freeze()をconst宣言直下でわかりやすく使うことで、オブジェクト内の値も不変であることを明示。

    キャンセル

  • 2017/09/10 12:37

    つまり、再代入が以降ないものに関してはconst使って、Object.freeze()がconst直下にない場合は、以降、オブジェクトの値は変わるかもしれないということを明示するみたいな感じでやってけばいいんですかね〜。

    キャンセル

  • 2017/09/10 14:42

    freezeはnestされたobjectの場合、子のobjectまでは凍結されないみたいですね。カスタムメソッド作んないといけないのか。。

    キャンセル

  • 2017/09/10 15:21

    Object.freezeはその弱点があるから駄目な子なんだよね。
    JavaScriptは潔癖になると制御コードだらけですぐ汚くなるから、ソースコードは簡素にまとめておいて運用ルールで頑張る言語だと思うよ。
    完全に縛るならElm-LangやPureScript、Scala.jsみたいなAltJS使った方が良いと思う。

    キャンセル

  • 2017/09/10 17:23 編集

    > 再代入が以降ないものに関してはconst使って、Object.freeze()がconst直下にない場合は、以降、オブジェクトの値は変わるかもしれないということを明示するみたいな感じでやってけばいいんですかね〜。
    わたしの場合、間違った使い方が出来ないように制限を設けるイメージで明示するとは少し違いますね。
    コードの意味が分かっている人であれば、constを使っていても使っていなくても、再代入されることで処理が破綻する事が分かるはずで、どちらかといえばこの手の強制力のある制限は「コードが分からない人向け」だと思っています。
    勿論、分かる人にはよりわかりやすくなるメリットはあります。

    > freezeはnestされたobjectの場合、子のobjectまでは凍結されないみたいですね
    JavaScriptはプロトタイプベースの言語ですが、nestされたオブジェクトのどこまでを影響範囲とするかが規定しづらい言語だと感じます。
    Node#CloneNodeではDOM APIの範疇でディープコピーするわけですが、Object.freezeがnestされたオブジェクトに対応するオプションがあったとして、
    - 同じ [[Prototype]] である限り、階層をまたいで参照するのか、全てのオブジェクトのプロパティを参照するのか
    - [[]Prototype]] 上に存在するプロパティも参照するのか
    という課題があります。

    ---
    Object.assignのディープコピー化にも同様の課題があり、更には、
    - コピーする対象の [[]Prototype]] までコピーするのか
    - コピーする対象の内部スロットまでコピーするのか
    という課題もあります。
    例えば、プロパティにnew WeakMapやnew Dateが存在した場合、同じ性質でかつ内部データまで同じでなければ使う意味がないですよね。
    しかし、内部スロットは他からはアクセスされない不可侵領域であるべきであって、内部スロットまでコピーされるのは問題です。

    [], {} のネスト構造で考えると現行仕様に不満も出てくると思いますが、汎用的な仕様として考えると、その希望に応えるのは難しいものがあるのではないかと思います。
    プリミティブ値の集合体としての役割であるなら、JSONを利用し、そうでなければコピーする基準を定義してから、自身で実装する事になります。

    キャンセル

+5

prefer-const を ESLint に入れている場合は「再代入しない変数」に関しては極力 const を使うように指摘されます。

ここから先は let がいいか const がいいかという議論ですが、 let にした所で大差はない一方で、 prefer-const を利用している一般的なプロダクトでは、 const 以外の変数にすることを極力避けます。

これは const を使う方が 「この変数はこれから再代入されることはない」 という認識を持ってプログラムを書くことができるからで、逆に let や var を使ってる場合は 「再代入されることがある特殊な変数なんだ」 というマーカーとして扱うことができるからです。

JavaScript ではありませんが、 Java の名著である Effective Java には「可変性を最小限にするべし」
というメッセージがあります。

http://hjm333.hatenablog.com/entry/2015/09/15/000644

これに倣ってなるべく let ではなく、 const を書く事を推奨する文化が生まれています。

ただし、 JavaScript は const にした所で、オブジェクトのプロパティフィールドには代入可能ですし、完璧な不変性を保つことはできません。そういう不変性を推奨する言語(Java, Scala, Haskell)からの書き方を多少なりとも輸入し、今時点では自分の観測範囲では let で書くよりも const で書く方が推奨されていると思います。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/09/10 11:56

    あ、すみません。質問の趣旨が不明確でした。。。「JavaScript は const にした所で、オブジェクトのプロパティフィールドには代入可能ですし、完璧な不変性を保つことはできません。」という話をふまえた上で、質問に掲載したようなコードの場合でも、const使うべきなのかなといった趣旨の質問となります。const使えば、以降のコードでその変数に再代入はされないってことは明確になるけど、オブジェクトのプロパティーに対する値は変わったりするから、逆に混乱のもとになりそうな気がしまして。

    キャンセル

  • 2017/09/10 14:09

    > オブジェクトのプロパティーに対する値は変わったりするから、逆に混乱のもとになりそうな気がしまして。

    これを気にするのであれば「constという変数宣言が誤解のもとになるからやめよう」というルールになり、「let」 を基本にすることになると思います。

    ただ実際には「変数宣言時にオブジェクトを不変にできる」という言語は多くないので、自分の感想としてはそこまで混乱の元にならないと思っています。

    Java の final しかり、 Scala の val しかり、宣言しただけで再代入禁止になるものの、不変にはなりません。

    自分が何かしら言語を教えるときには「不変」と「再代入禁止」を分けて考えた方が良いと教えています。 その上でJavaScriptで ESLint を使った場合に `prefer-const` にしただけでは「不変」ではない事も教えていますが、僕は `prefer-const` にするように推奨しています。

    理由は前に書いたとおりですが、「完全なる不変性が保たれないから(100%の安全を担保できないから)」といって、「再代入可能にして可変性を増やすべきではない(危険性を増やすべきではない)」という理由です。

    キャンセル

  • 2017/09/10 14:45

    constは再代入不可という意味であることを頭に叩き込んで、その意味の為だけにconstを使っていこうと思います。

    キャンセル

+2

まぁ、作ったオブジェクトを後からごちゃごちゃ弄るなって話だね。
ライブラリや組み込みメソッドがバリバリなJavaScriptでは現実的にはかなり難問なんだけどね…

JavaScript関数型プログラミング 複雑性を抑える発想と実践法を学ぶ の本では、
オブジェクトにする場合は、毎回自分自身をnewし直して値を更新出来るように備えようというアプローチが書いてあったね。

単純なObjectでやりたいならこんな感じのアプローチ。

const obj = {id: 3};
const obj2 = Object.assign({}, obj, {id: 4})

console.log(obj);
// {id: 3}
console.lo(obj2);
// {id: 4}

後者の質問だけど、そのd3.scaleTime.rangeは破壊的なメソッドなのかな?
d3に関しては使った事無いからよく分からないけど、
サンプルを軽く眺めた限り、jQueryと同じパターン※で非破壊的な作りだと思うんだよね。

もし破壊的じゃないなら、rangeメソッドいくら叩いてもオブジェクトの値は変更されない。
つまりconstの方が適切だよね、一回確認してみてくれる?

※jQueryのパターン
毎回thisを返しまくって、メソッドチェーンを実現している。
途中の結果を何時でも変数に入れてキャッシュ出来るように、各メソッドは毎回新しいインスタンスを作り直している。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/09/10 13:24

    ```
    let scale = d3.scaleLinear();
    console.log(scale.domain()); // ▶︎(2) [0, 1]
    let scale2 = scale.domain([0, 100]);
    console.log(scale.domain()); // ▶︎(2) [0, 100]
    console.log(scale2.domain()); // ▶︎(2) [0, 100]
    ```

    キャンセル

  • 2017/09/10 13:25 編集

    d3には破壊的メソッドもあれば、非破壊的メソッドもあります。上記コードは破壊的メソッドと言って良いのですよね?

    キャンセル

  • 2017/09/10 13:28 編集

    > const obj2 = Object.assign({}, obj, {id: 4})
    既存のオブジェクトに変更を加えたい場合は、immutable意識するってことに徹すれば、あとは、単純に再代入出来ないって意味だけのconstを気にせず使えば良いのかもしれませんね。

    JS関数型プログラミングの本は2冊書いましたが、絶賛積読中です!掲載いただいた新書は注文してないですが、かいたい。。。

    キャンセル

  • 2017/09/10 14:56

    これは破壊的だね、イケてないなぁ…

    キャンセル

  • 2017/09/10 15:33

    前にdeep copyできてなかったオブジェクトをd3に渡して激ハマりしました。。。

    キャンセル

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

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

関連した質問

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

  • JavaScript

    14778questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • Node.js

    1678questions

    Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

  • ESLint

    19questions

    ESLintは、JavaScriptのための構文チェックツール。全検証ルールを自由に on/offでき、独自のプロジェクトに合わせたカスタムルールを容易に設定することが可能。公開されている様々なプラグインを組み込んで使用することもできます。