3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

JavaScriptのSpreadOperatorはhasOwnPropertyを見ていない?

Last updated at Posted at 2016-12-05

何かおかしいところあったら教えてください。

ことの発端

テスト用のデータとして、['test1', 'test2', 'test3']のように、100要素くらいある配列をサクッと生成してみたかった。

そして最終的に行き着いたのが次のコードだった。

[...(Array(10))].map((_, i) => `test${i}`);

その後調べてみると、より正しそうな方法を書いたブログを見つけたので、実際に使うときはここを参考にすると良さそう。

JavaScriptで0からn-1までを要素にもつArrayを作成する方法

さて、上記のブログで目的は達成されたが、何故自分が書いたコードが動いていたのだろう。色々と試してみた。

動作確認環境:Chrome 55.0

JavaScriptの配列の不思議

これは割と知っている人も多いことだと思うけど、Array(10)[10]は違う。前者は「サイズが10の配列を作成」で、後者は「10という要素を持つ配列を作成」だ。

これを利用して、「10回ループを回すだけ」の目的で配列を作ろうとした。そのときのコードが以下。

Array(10).forEach(e => console.log('hoge'));

ただし、これは期待通りに動かない。原因は、Array()lengthプロパティは持つが、配列の各要素は持たない配列を生成するためだ。

よくわからないことを言っている気がするけど、次のサンプルを見ると明確だ。

Array(10).length;
// => 10

Array(10).hasOwnProperty(0);
// => false

[10].hasOwnProperty(0);
// => true

ここからわかる事は、ArrayのmapforEachなどの関数は、lengthプロパティだけでなくhasOwnProperty(又はそれに類するもの)を元にループを回すか判定しているということだ。

そんなこんなでArray(10).forEach()というコードは動かないことがわかった。

そこで、(これは完全に思いつきで)ES2016のSpread Operatorを使ってみたらどうだろうと、試してみた。Spread Operatorは、オブジェクトや配列を展開してくれる式だ。

例えば、次のように使える。

const aray1 = [1, 2, 3];
const array2 = [...array1, 4, 5];

console.log(array2);
// => [1, 2, 3, 4, 5]

今回のケースだと、こういう形になる。

[...(Array(10))].forEach(e => console.log('hoge'));

すると、これは期待通りに動き、hogeが10回出力される結果となった。Spread Operatorにより、lengthのみだった配列が、要素を持った通常の配列に変換された。

Array(10)
// => [undefined × 10]

[...(Array(10))]
// => [undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined]

つまりSpread Operatorは、配列が実際に要素を持っているかどうかによらず、lengthの情報から配列の展開を行っているらしい。Array()で初期化した配列は要素を持たないので、undefinedを10個持つ配列に変換されたようだ。

ちなみにArray.from()でもSpreadOperatorと同様の結果になった。

Array.from(Array(10))
// => [undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined]

結論

mapforEachhasOwnProperty相当の評価を行ってループを回しているが、Spread Operatorではその判定は無い。

さて、これが何の役に立つのか...

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?