2017/01/29

ES2015(ES6)の分割代入でCannot set property of undefinedやis not definedというエラーがでる

AとBの値を入れ替えるときに分割代入(Destructuring assignment)構文をつかうと、テンポラリ変数を使わなくてすむ。
ということで、配列の中身をシャッフルする関数で分割代入構文を使ったのだが「Cannot set property 'hoge' of undefined」や、定義したはずの変数が「'hoge' is not defined」というエラーがでてしまった。

いろいろ調べたので結果をまとめる。


問題のコード


const values = [1,2,3,4,5,6,7,8,9,10]

let i = values.length
while(i--) {
  const r = Math.floor(Math.random() * i)
  [values[i], values[r]] = [values[r], values[i]]
}

console.log(...values)

このコードを実行すると、分割代入構文のところで「'r' is not defined」というエラーがでる。
分割代入構文の直前に「console.log(r)」を入れると、ちゃんと変数rは定義されている。それなのに正常に動作しない。

デバッグしようと、分割代入構文の直前に「debugger」を入れると正常に動作した。

謎い。。。




問題を単純化してみる


前述のコードだとうまくいかなかったので、もっと単純化してみる。
var a = 1
var b = 2
console.log(a,b)
[a, b] = [b, a]
console.log(a,b)

このコードを実行すると「Uncaught TypeError Cannot set property '2' of undefined」というエラーがでる。これもまた分割代入構文の直前に「debugger」を入れてみたところ正常に動作した。

謎い。。。



MDNのサンプルどおり書いてみる


単純化してもダメだったので、MDNに載っている「変数の入れ替え」のサンプルコードをそのまま実行してみる。
var a = 1;
var b = 3;

[a, b] = [b, a];
console.log(a, b);

正常に動作した?!


「問題を単純化してみる」で書いたコードとMDNのサンプルを比較したところ、違いは「セミコロンの有無」だけ

ということで、前述の2つのコードにセミコロンを追加したところ...正常に動作した?!?!

どうやら分割代入の[](ブラケット記号)が直前の処理の続きとして解釈されていたらしい。debuggerは制御系のステートメントなので、他の処理部とは明確にわけられるので、独立した処理と解釈されエラーにならなかった。


vue-cliでLintにStandardを選ぶとセミコロンがあると怒られてしまう。また最近Pythonの勉強を再開したので、「セミコロン」=「省くべきもの」だと錯覚していたため、今回の問題にぶちあたってしまった。


普通にJavaScriptを書くときは、セミコロンを付けましょー!



参考サイト





以上

written by @bc_rikko

0 件のコメント :

コメントを投稿