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

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

新規登録して質問してみよう
ただいま回答率
85.35%
JavaScript

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

Q&A

8回答

734閲覧

constな配列を操作することは一般的に許されていないか

toshiyan

総合スコア74

JavaScript

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

0グッド

0クリップ

投稿2020/10/02 14:06

以下のコードでは、定数として宣言した配列を操作しています。

javascript

1const arr = [] 2arr.push(1)

「この場所以降では決して配列を変更しない」ということを示したいという思いでこのように記述しているのですが、やはりあまり好かれない書き方でしょうか?

もしバッドプラクティスとして一般的に認知されているのでしたら、こういった記述の仕方は控えようと思います。世間がどのように感じるかを知りたいです。回答よろしくお願いします。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答8

0

べき論

回答で「べき論」と「可否論」が混在している気がします。

「この場所以降では決して配列を変更しない」ということを示したいという思いでこのように記述しているのですが、やはりあまり好かれない書き方でしょうか?
もしバッドプラクティスとして一般的に認知されているのでしたら、こういった記述の仕方は控えようと思います。世間がどのように感じるかを知りたいです。回答よろしくお願いします。

これはべき論ですが、そもそも、プログラミングに一般的にこうというルールはないので、気にしないで下さい。
コーディング規約の話なら、有名どころのコーディング規約を複数読んで比較検討すればよい話ですが、「一般的」という論調になると

  • varは古いので使うべきでは有りません。let,constを使いましょう。
  • アロー関数こそが現在の流行です。関数宣言は捨てましょう。

「一般的」にはこれらと同じにおいを感じます。

  • varは関数スコープで宣言できるのでまだ使い道があります
  • アロー関数だけを使ってイベントハンドラ関数でthis値がとれないと嘆いている人を見たことがあります

結局、古いのが問題なのではなく、古い機能が現在書いているコードにマッチするかが重要で、新しくても古くてもそれは同じです。
同じように「一般的だから使う」のではなくて「その機能が要件にマッチしているから使う」のだと思うのです。

const と Object.freeze()

const は再代入を禁止する機能を持ちますが、プロパティの書き換えを禁止するわけではありません。

JavaScript

1const a = []; 2a.push(1); 3a = 1; // TypeError: Assignment to constant variable.

Object.freeze はプロパティの書き換えを禁止しますが、再代入を禁止するわけではありません。

JavaScript

1let a2 = []; 2a2 = []; 3Object.freeze(a2); 4a2.push(1); // TypeError: Cannot add property 0, object is not extensible

両方を使えば、再代入もプロパティ書き換えも禁止されます。

JavaScript

1const a3 = Object.freeze([]); 2a3.push(1); // TypeError: Cannot add property 0, object is not extensible

これは一般的だから使うわけでは有りません。
「再代入禁止」と「プロパティ書き換え禁止」の要件がある時に使うのです。

各々の機能を把握すれば、使うべき場面は自ずと判断できると思います。

Re: toshiyan さん

投稿2020/10/03 04:42

think49

総合スコア18189

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

もしバッドプラクティスとして一般的に認知されているのでしたら、こういった記述の仕方は控えようと思います。世間がどのように感じるかを知りたいです。回答よろしくお願いします。

そんなことはありません。
むしろ、arrを再代入させたくないのであれば、むしろ、constで宣言すべきでしょう。

ただし、JavaScriptでは、このような仕様(定数宣言したオブジェクトにも、プロパティの再代入は可能という仕様)ですが、
他の言語では、定数定義をしたオブジェクトには、pushのようなこともできない言語の方が多いように思うので、注意が必要です。

例えば、Swiftは、letが定数宣言なのですが、
letで宣言された配列変数には、要素を追加もできません。
(イミュータブルという)
対して、JavaScriptは、いかなる場合でも、
再宣言を除き、オブジェクトに関しては、常にミュータブルとなります。
(再宣言、再代入はできないが、プロパティなど、中身は再代入や追加、削除が可能)

投稿2020/10/02 17:08

miyabi_takatsuk

総合スコア9555

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

toshiyan

2020/10/03 02:02

回答ありがとうございます! JavaScriptでは受け入れられている記述なのですね。他の言語経験者が見ると「ん?」と思う記述なので使うのが悩むところです。
miyabi_takatsuk

2020/10/03 12:50

JavaScriptに限らず、言語間ではこういった細かな仕様の違いがありますので、新しく学ぶ、使う言語は勉強が必要ですね。 JavaScriptではむしろ、letで宣言することもやめよう的な書き方さえ存在します。 いろいろと緩い言語なので、 そういった、個人や現場間でいろいろな書き方や、考え方が存在するのかと思います。
guest

0

constな配列

というのが、const arr = []のことなら、constなのは変数arrであって、配列は別にconstという概念は無いでしょう。

配列を変更しないのなら、Object.freeze()でしょう。

そんなことより、;を付けてないことの方が気になります。

投稿2020/10/02 15:14

otn

総合スコア85901

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

miyabi_takatsuk

2020/10/02 16:59

セミコロンレスで書く人多いですよね。 でも何も知らないうちに、省略できるんだ!って感じではやるべきではない、と思います。 (ASIを理解してやっているならまだ別ですが)
toshiyan

2020/10/03 02:12

回答ありがとうございます! なるほど…配列の中身を変更したくない時は、明示的にフリーズするといいのですね。参考になります。 セミコロンを使っていない理由はシンプルで、今参加しているプロジェクトがセミコロンを使わない文化だからですね。
miyabi_takatsuk

2020/10/03 13:06 編集

文化、ですか・・・。 その文化にしてる理由などは、確認したほうがいいかもしれませんね。 JavaScriptは、そもそも仕様としてセミコロンが必要で、その補填をする機能がある、というだけなので。 (それ故に、書き方を間違えると、その補填機能のASIが下手に効いてエラーになる) ASIがどういう挙動をするかを認識した上で、記法をルール化してるなら、問題ないと思います。
guest

0

TypeScriptではconstと別にreadonlyが存在します。

typescript

1const readOnlyArr: readonly number[] = [1]; 2 3// コンパイルエラー 4readOnlyArr.push(2); 5 6const constArr: number[] = [3]; 7 8// こちらは問題なし 9constArr.push(4);

投稿2020/10/02 22:29

maisumakun

総合スコア146018

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2020/10/02 22:51

こうして併存していると、「constはあくまで『変数に入れたオブジェクトが入れ替わらない』という意味しか持たない」ということがはっきりする感じもします。
toshiyan

2020/10/03 02:00

回答ありがとうございます! なるほど…。TypeScriptでは型宣言で変更不可にできるのですね。参考になります。
guest

0

const
上記URLにもあるけど

// 配列も同じ const MY_ARRAY = []; // 配列にアイテムをプッシュすることができる MY_ARRAY.push('A'); // ["A"] // しかし、新しい配列を代入するのはエラーになる - Uncaught TypeError: Assignment to constant variable. MY_ARRAY = ['B'];

constの使い方は「この変数は定数です」(値が変化しない)と指し示す物だから。
初期値を設定する意味でのpushなら書き方的にOKだが
通常の変数の様に初期値から値を変更するのは書き方的にNG

もしpushがダメなら

const msec = 24 * 60 * 60 * 1000;

みたいな計算式自体NGになると思うんだけど

追記
例えば
「共通処理でinputの初期値を定数として持っておきたい
となった時、初期値なので定数constで指定となるが
配列の長さは画面によって可変し、また順番もあるので
[.push]での書き方のほうが指定しやすい。」
という事だと理解しています。

投稿2020/10/02 15:51

編集2020/10/03 03:25
kuma_kuma_

総合スコア2506

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

momon-ga

2020/10/02 23:47

再代入と変更を区別せず説明しているように見えますが const arr = [1]; arr[0] = 3; の場合も、書き方的にOKということでしょうか?
toshiyan

2020/10/03 02:09

回答ありがとうございます! JavaScriptをよく知っている人であれば普通に受け入れられる記述みたいですね。
kuma_kuma_

2020/10/03 03:04

> const arr = [1]; // これはOK > arr[0] = 3; // これはNG (Firefoxで確認したら変数自体が消えました) 現実的にJavascript自体が処理を受け入れている以上 完全に「pushの書き方がいけない」とは言えないと私は思っています。 ただ使い方として「定数」の概念から外れなければ良いという事です。
guest

0

個人的には、コードリードしているときに「const宣言された配列の要素は変更されない」とは思っていないです。なので、気になりません。
その他のオブジェクトも同様です。たとえば、DOMオブジェクトはユーザーの操作によってプロパティが変化しうると思いますが、これがconstで宣言されていても特段の違和感はありません。

投稿2020/10/03 04:45

Lhankor_Mhy

総合スコア36960

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

あまり好かれない書き方でしょうか?

破壊的変更を加えることは一般的に、あまり好かれない書き方だと思います。

以下のように新しい変数(定数)に代入すると良いです。

const arr = [1, 2, 3] const newArr = arr.concat(4) console.log(arr) // [1, 2, 3] console.log(newArr) // [1, 2, 3, 4]

投稿2020/10/02 16:06

murabito

総合スコア108

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

toshiyan

2020/10/03 02:07

回答ありがとうございます! 今の議論の対象は「constな配列に破壊的操作をすること」であって「配列に破壊的操作をすること」ではないため、回答が少しずれている気がします。
murabito

2020/10/03 03:51 編集

「この場所以降では決して配列を変更しないということを示したい」ということであれば、対象の配列をdeep freezeさせるしか、JavaScriptでは方法がないです。ちなみに、constな配列かconstな配列でないかに関わらず、破壊的変更は避けたいため、結論一緒です。コードレビュー時に質問にあるようなコードをみかけたら、指摘が入ると思うので、わざわざ、deep freezeによって、対象の配列に変更が加わらないことを示さなくても大丈夫かと。
guest

0

constな配列を操作することは一般的に許されていないか

一般的にはしないと思います。
配列に限ればconstで定義したからには、以降の処理で要素に変化が無い方がコードが読み易い。直観的です。
だからdeveloper.mozilla.orgのサンプルコードでもletを使っているんじゃないかと思います。

操作の対象をオブジェクトにまで話を広げた場合は、const定義以降は中身を変更しないという基本的な考えは踏襲しつつも、constに対してappendするようなコードが信頼出来るドキュメント上で見つかればそれを真似ます。

投稿2020/10/03 04:19

hentaiman

総合スコア6426

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問