JavaScript配列を作成するためのハック

JavaScriptで配列を作成および複製するための洞察に満ちたヒント。

すべてのプログラミング言語の非常に重要な側面は、その言語で使用できるデータ型と構造です。ほとんどのプログラミング言語は、複雑なデータを表現および操作するためのデータ型を提供します。PythonやRubyなどの言語を使用したことがある場合リストセットタプルハッシュ辞書などのデータ型を見たことがあるはずです。

JavaScriptでは、複雑なデータ型はそれほど多くありません。配列オブジェクトがあるだけです。ただし、ES6では、シンボルセットマップなど、いくつかのデータ型と構造が言語に追加されました。

JavaScriptの配列は、長さプロパティと整数プロパティをインデックスとして持つ高レベルのリストのようなオブジェクトです

この記事では、新しいJavaScript配列を作成したり、既存の配列を複製したりするためのハックをいくつか紹介します。

配列の作成:配列コンストラクター

配列を作成するための最も一般的な方法は、配列リテラル構文を使用することです。これは非常に簡単です。ただし、配列を動的に作成する場合は、配列リテラル構文が常に最適な方法であるとは限りません。別の方法は、Arrayコンストラクターを使用することです。

これは、Arrayコンストラクターの使用法を示す簡単なコードスニペットです。

前のスニペットから、Arrayコンストラクターが受け取る引数に応じて異なる方法で配列を作成することがわかります。

新しい配列:定義された長さ

Array与えられた長さの新しいものを作成するときに何が起こるかをもっと詳しく見てみましょう。コンストラクターlengthは、キーを設定せずに、配列のプロパティを指定された長さに設定するだけです。

上記のスニペットから、配列内の各キーがの値に設定されていると思われるかもしれませんundefined。しかし、実際には、これらのキーは設定されていません(存在しません)。

次の図はそれをより明確にします:

これによりmap()、などの配列反復法のいずれかを使用しようとしたり、配列を操作しfilter()たりすることは無意味になりますreduce()。配列内の各インデックスに数値5として数値を入力するとします。次のことを試みます。

map()インデックスプロパティが配列に存在しないため、ここでは機能しなかったことがわかりlengthます。プロパティのみが存在します。

この問題を修正するさまざまな方法を見てみましょう。

1. Array.prototype.fill()を使用する

このfill()メソッドは、開始インデックスから終了インデックスまでの配列のすべての要素を静的な値で埋めます。終了インデックスは含まれていません。詳細については、fill()こちらをご覧ください。

fill()ES6をサポートするブラウザでのみ機能することに注意してください。

簡単な図を次に示します。

ここでは、作成した配列のすべての要素をで埋めることができました5。このfill()メソッドを使用して、配列のさまざまなインデックスに任意の静的値を設定できます。

2. Array.from()の使用

このArray.from()メソッドはArray、配列のようなオブジェクトまたは反復可能なオブジェクトから、浅くコピーされた新しいインスタンスを作成します。詳細については、Array.from()こちらをご覧ください。

Array.from()ES6をサポートするブラウザでのみ機能することに注意してください。

簡単な図を次に示します。

ここで、をundefined使用して配列の各要素に真の値を設定しましたArray.from()。この手段は、私たちは今の方法のように先に行くと、使用可能.map().filter()インデックスのプロパティは、現在存在しているため、アレイ上。

注目に値するもう1つの点Array.from()は、マップ関数である2番目の引数を取ることができるということです。配列のすべての要素で呼び出されます。これにより、.map()後の呼び出しが冗長になりArray.from()ます。

簡単な例を次に示します。

3.スプレッド演算子の使用

スプレッド演算子...ES6で追加された()を使用して、配列の要素を分散し、欠落している要素をの値に設定できますundefined。これによりArray.from()、配列のみを引数として単純に呼び出すのと同じ結果が得られます。

スプレッド演算子の使用の簡単な図を次に示します。

あなたは先に行くなど、使用方法することができます.map()し、.filter()インデックスプロパティは、現在存在しているため、アレイ上。

Array.of()の使用

Arrayコンストラクターまたは関数を使用して新しい配列を作成するときに見たArray.of()ように、非常によく似た方法で動作します。実際には、唯一の違いArray.of()とはArray、彼らが彼らに渡された1つの整数引数を処理する方法です。

一方Array.of(5)、単一の要素、、5および長さプロパティが1Array(5)の新しい配列を作成し、5つの空のスロットと長さプロパティが5。の新しい空の配列を作成します。

var array1 = Array.of(5); // [5] var array2 = Array(5); // Array(5) {length: 5}

この大きな違いに加えてArray.of()Arrayコンストラクターと同じように動作します。詳細については、Array.of()こちらをご覧ください。

Array.of()ES6をサポートするブラウザでのみ機能することに注意してください。

配列への変換:配列のようなものと反復可能なもの

JavaScript関数を十分に長く作成している場合は、argumentsオブジェクトについて既に知っている必要があります。これは、関数が受け取った引数のリストを保持するためにすべての関数で使用できる配列のようなオブジェクトです。けれどもarguments、オブジェクトが非常に配列のように見える、それはへのアクセス権がないArray.prototype方法を。

ES6より前は、argumentsオブジェクトを配列に変換しようとすると、通常、次のようなコードスニペットが表示されます。

Array.from()やスプレッド演算子、あなたは、便利な任意の配列のようなオブジェクトを配列に変換することができます。したがって、これを行う代わりに:

var args = Array.prototype.slice.call(arguments);

次のいずれかを実行できます。

// Using Array.from() var args = Array.from(arguments); // Using the Spread operator var args = [...arguments];

これらは、次の図に示すように、反復可能オブジェクトにも適用されます。

ケーススタディ:範囲関数

先に進む前のケーススタディとして、先ほど学習しrange()た新しい配列ハックを実装するための簡単な関数を作成します。この関数には次の署名があります。

range(start: number, end: number, step: number) => Array

コードスニペットは次のとおりです。

このコードスニペットではArray.from()、動的な長さの新しい範囲配列を作成し、マッピング関数を提供することにより、順次増分された数値を入力していました。

上記のコードスニペットは、ポリフィルを使用する場合を除いて、ES6をサポートしていないブラウザーでは機能しないことに注意してください。

range()上記のコードスニペットで定義された関数を呼び出した結果は次のとおりです。

Codepenで次のペンを実行すると、ライブコードデモを入手できます。

アレイのクローニング:課題

JavaScriptでは、配列とオブジェクトは参照型です。つまり、変数に配列またはオブジェクトが割り当てられると、変数に割り当てられるのは、配列またはオブジェクトが格納されていたメモリ内の場所への参照です。

配列は、JavaScriptの他のすべてのオブジェクトと同様に、参照型です。これは、配列が値ではなく参照によってコピーされることを意味します。

この方法で参照型を保存すると、次のような結果になります。

1.同様の配列は等しくありません。

ここでは、array1array2は一見同じ配列仕様を含んでいますが、それらは等しくないことがわかります。これは、各配列への参照がメモリ内の異なる場所を指しているためです。

2.配列は、値ではなく参照によってコピーされます。

ここでは、にコピーしようとしますarray1array2、基本的には、を指しarray2ているメモリ内の同じ場所を指しているarray1ことです。したがって、とは両方ともメモリ内の同じ場所array1array2指し、等しい。

これはarray2、最後のアイテムを削除して変更を加えると、の最後のアイテムarray1も削除されることを意味します。これは、実際にはメモリに格納されている配列に変更が加えられたのに対し、array1array2は配列が格納されているメモリ内の同じ場所へのポインタにすぎないためです。

アレイのクローニング:ハック

1. Array.prototype.slice()を使用する

このslice()メソッドは、配列を変更せずに、配列の一部の浅いコピーを作成します。詳細については、slice()こちらをご覧ください。

秘訣は、引数を1つだけslice()持つか、0引数をまったく使わずに呼び出すことです。

// with O as only argument array.slice(0); // without argument array.slice();

これは、以下を使用して配列を複製する簡単な図ですslice()

ここarray2array1は、同じアイテムと長さののクローンであることがわかります。ただし、それらはメモリ内の異なる場所を指しているため、結果として等しくありません。またarray2、最後のアイテムを削除してに変更を加えても、変更されarray1ないままであることに注意してください。

2. Array.prototype.concat()を使用する

このconcat()メソッドは、2つ以上の配列をマージするために使用され、元の配列は変更されないまま、新しい配列になります。詳細については、concat()こちらをご覧ください。

秘訣は、引数としてconcat()空のarray([])を使用するか、引数をまったく使用せずに呼び出すことです。

// with an empty array array.concat([]); // without argument array.concat();

で配列を複製することは、concat()を使用することと非常に似ていslice()ます。これは、以下を使用して配列を複製する簡単な図ですconcat()

3. Array.from()の使用

前に見たようArray.from()に、元の配列の浅いコピーである新しい配列を作成するために使用できます。簡単な図を次に示します。

4.配列分解の使用

ES6では、ツールボックスに、破壊拡散などのより強力なツールがいくつかあります。演算子矢印関数など。破棄は、配列やオブジェクトなどの複雑なタイプからデータを抽出するための非常に強力なツールです。

秘訣は、次のスニペットに示すように、配列の破棄と拡散演算子の組み合わせを含む、レストパラメーターと呼ばれる手法を使用することです。

let [...arrayClone] = originalArray;

上記のスニペットarrayCloneは、のクローンであるという名前の変数を作成しますoriginalArray。配列の非構造化を使用して配列を複製する簡単な図を次に示します。

クローニング:浅い対深い

これまでに調査したすべてのアレイクローン作成手法により、アレイの浅いコピー作成されます。配列にプリミティブ値のみが含まれている場合、これは問題になりません。ただし、配列にネストされたオブジェクト参照が含まれている場合、配列が複製されても、それらの参照はそのまま残ります。

これは非常に簡単なデモンストレーションです。

のネストされた配列を変更すると、のネストされた配列array1も変更され、array2その逆も同様であることに注意してください。

この問題の解決策は、配列のディープコピーを作成することであり、これを行うにはいくつかの方法があります。

1.JSONテクニック

配列のディープコピーを作成する最も簡単な方法は、の組み合わせを使用することであるJSON.stringify()JSON.parse()

JSON.stringify()JavaScript値を有効なJSON文字列にJSON.parse()変換し、JSON文字列を対応するJavaScript値またはオブジェクトに変換します。

簡単な例を次に示します。

JSON手法には、特に文字列、数値、ブール値以外の値が含まれる場合にいくつかの欠陥があります。

JSON手法のこれらの欠陥は、主に、JSON.stringify()メソッドが値をJSON文字列に変換する方法に起因する可能性があります。

これは、JSON.stringify()ネストされた関数を含む値を試行する際のこの欠陥の簡単なデモンストレーションです。

2.ディープコピーヘルパー

JSON手法の実行可能な代替手段は、配列であろうとオブジェクトであろうと、参照型を複製するための独自のディープコピーヘルパー関数を実装することです。

これは非常にシンプルでミニマルなディープコピー関数deepCloneです:

いくつかのJavaScriptライブラリですぐにわかるように、これは現在のディープコピー関数の中で最高のものではありませんが、かなりの程度までディープコピーを実行します。

3.JavaScriptライブラリの使用

先ほど定義したディープコピーヘルパー関数は、複雑なオブジェクトや配列内にネストされている可能性のあるすべての種類のJavaScriptデータのクローンを作成するのに十分な堅牢性を備えていません。

LodashjQueryなどのJavaScriptライブラリは、さまざまな種類のJavaScriptデータをサポートする、より堅牢なディープコピーユーティリティ関数を提供します。

_.cloneDeep()Lodashライブラリから使用する例を次に示します。

これは同じ例ですが$.extend()、jQueryライブラリから使用しています。

結論

この記事では、配列のようなオブジェクトや反復可能オブジェクトを配列に変換するなど、新しい配列を動的に作成し、既存の配列を複製するためのいくつかの手法を探ることができました。

また、ES6で導入された新機能と拡張機能のいくつかにより、アレイに対して特定の操作を効果的に実行できるようになることも確認しました。

配列のクローン作成と拡散には、destructuringやspread演算子などの機能を使用しました。この記事から、破壊について詳しく知ることができます。

クラップ&フォロー

この記事が洞察に満ちていると感じた場合は、気にしないのであれば、自由に拍手を送ることができます。

また、Medium(Glad Chinda)で私をフォローして、役立つと思われるより洞察に満ちた記事を入手することもできます。Twitter(@gladchinda)で私をフォローすることもできます。

ハッピーハッキング…