web-dev-qa-db-ja.com

スプレッド構文ES6

次のサンプルコードを検討してください

var x = ["a", "b", "c"];
var z = ["p", "q"];

var d = [...x, ...z];

var e = x.concat(z);

ここで、deの値はまったく同じであり、["a", "b", "c", "p", "q"]と等しいので、

  1. これら2つの違いは正確には何ですか?
  2. どちらがより効率的で、なぜですか?
  3. スプレッド構文の使用は正確には何ですか?

正式な広大な言語でこれらの小さなショートカットを導入すると、見過ごされているバグが残る可能性があると思いませんか。つまり、それはかなり不要であるか、適切に必要であるとは認識していません。

27
void
  1. 与えられたあなたの例では、2つの間に本質的に違いはありません
  2. .concat大幅に効率的:http://jsperf.com/spread-into-array-vs-concat...(スプレッド)は単なるシンタックスシュガーであるため配列を展開するためにインデックスを明示的に反復する、より基本的な基本構文。
  3. Spreadを使用すると、より不格好な直接配列操作に加えて、糖化された構文が可能になります

上記の#3を拡張するために、スプレッドの使用はやや不自然な例です(ただし、実際に頻繁に表示される可能性があります)。 Spreadは、たとえば、引数リスト全体を関数本体の.callに渡す必要がある場合に役立ちます。

function myFunc(){
    otherFunc.call( myObj, ...args );
}

versus

function myFunc(){
    otherFunc.call( myObj, args[0], args[1], args[2], args[3], args[4] );
}

これは別の恣意的な例ですが、spread演算子が冗長で不格好な状況で使用するのに適している理由は少し明確です。

として @ loganfsmyth指摘

Spreadは、任意の反復可能なオブジェクトでも機能します。つまり、Arraysだけでなく、MapSetなどでも機能します。

これは素晴らしい点であり、ES5で実現することは不可能ではありませんが、spread演算子で導入された機能は、新しい構文で最も役立つ項目の1つであるという考えに追加されます。


この特定のコンテキストでのspread演算子の実際の基礎となる構文については(...も「rest」パラメーターになる可能性があるため)、 仕様 を参照してください。上で書いたように、「インデックスを明示的に反復して配列を拡張する、より基本的な基本構文」で十分ですが、実際の定義では、後続の変数にGetValueGetIteratorを使用します。 。

23
rockerest

質問を順不同にして、基本的な質問から始めましょう:スプレッド構文の使用は正確には何ですか?

Spread構文は基本的に、配列やオブジェクトなどのiterableの要素を解凍します。または、 スプレッド構文に関するMDN Web Docs からのより詳細な説明については:

Spread構文を使用すると、配列式や文字列などの反復可能オブジェクトを、0個以上の引数(関数呼び出しの場合)または要素(配列リテラルの場合)が予想される場所で展開したり、オブジェクト式を0個以上の場所で展開したりできます。キーと値のペア(オブジェクトリテラル用)が必要です。

以下は、spread構文の典型的な使用例の簡単な例と、spread構文とrestパラメーターの違いの例です(同じように見えるかもしれませんが、ほぼ反対の機能を実行します)。

関数呼び出し:

_const multiArgs = (one, two) => {
   console.log(one, two);
}

let args = [1, 2];
multiArgs(...args);
// 1 2_

配列または文字列リテラル:

_let arr1 = [2, 3];
let arr2 = [1, ...arr1, 4];
console.log(arr2);
// [1, 2, 3, 4]

let s = 'split';
console.log(...s);
// s p l i t_

オブジェクトリテラル:

_let obj1 = { 1: 'one' };
let obj2 = { 2: 'two' };
let obj3 = { ...obj1, ...obj2 };
console.log(obj3);
// { 1: 'one', 2: 'two' }_

RESTパラメーターの構文はspread構文と同じではありません:

RESTパラメーター 構文はspread構文と同じように見えますが、実際には不明な数の関数の引数を配列として表します。したがって、RESTパラメーターは、反復可能を「アンパック」するのではなく、実際には複数の引数を配列にパッケージ化します。

_const multiArgs = (...args) => {
   console.log(args);
}

multiArgs('a', 'b', 'c');
// ['a', 'b', 'c']_

構文のパフォーマンス/効率を広げる:

他の方法と比較した効率についての質問に対処するために、唯一の正直な答えは「それは依存する」ということです。ブラウザは常に変化し、特定の関数に関連付けられたコンテキストとデータは大きく異なるパフォーマンス結果を生成するため、さまざまな配列やオブジェクトのメソッドよりも、拡散構文が驚くほど高速であり、途方もなく遅いことを示唆する、あらゆる種類の競合するパフォーマンスタイミングを見つけることができます。同様の目的を達成するために使用します。結局、速度の最適化が重要である状況は、コードとデータの詳細を無視する単純な関数の一般的なタイミングに依存するのではなく、比較テストする必要があります。

concat()との比較

そして最後に、スプレッド構文と質問コードに示されている concat() の違いに関する簡単なコメント。違いは、spread構文は配列を連結するだけでなく多くの目的で使用できることですが、concat()はIEなどの古いブラウザーで機能します。古いブラウザとの互換性を気にせず、速度の微調整が不要な状況では、スプレッド構文とconcat()のどちらを選択するかは、読みやすいものを選択するだけです。arr3 = arr1.concat(arr2)または_arr3 = [...arr1, ...arr2]_。

2
benvc

この例の出力は同じですが、内部では同じ動作ではありません。

考えてみてください(ブラウザのコンソールを確認してください):

var x = [], y = [];

x[1] = "a";
y[1] = "b";

var usingSpread = [...x, ...y];
var usingConcat = x.concat(y);

console.log(usingSpread); // [ undefined, "a", undefined, "b"]
console.log(usingConcat); // [ , "a", , "b"] 

console.log(1 in usingSpread); // true
console.log(1 in usingConcat); // false

Array.prototype.concat は配列内の 空のスロット を保持し、Spreadはそれらをundefined値に置き換えます。

Enter Symbol.iterator and Symbol.isConcatSpwritten

Spread 演算子は、@@iterator記号を使用して、次のような配列および配列のようなオブジェクトを反復処理します。

  • Array.prototype
  • TypedArray.prototype
  • String.prototype
  • Map.prototype
  • Set.prototype

(そのため、それらにfor .. ofを使用できます)

デフォルトのiteratorシンボルをオーバーライドして、spread演算子がどのように動作するかを確認できます。

var myIterable = ["a", "b", "c"];
var myIterable2 = ["d", "e", "f"];

myIterable[Symbol.iterator] = function*() {
  yield 1;
  yield 2;
  yield 3;
};

console.log(myIterable[0], myIterable[1], myIterable[2]); // a b c
console.log([...myIterable]); // [1,2,3]

var result = [...myIterable, ...myIterable2];
console.log(result); // [1,2,3,"d","e","f"]

var result2 = myIterable.concat(myIterable2);
console.log(result2); // ["a", "b", "c", "d", "e", "f"]

一方、@@isConcatSpreadable

Trueの場合、オブジェクトをArray.prototype.concatによって配列要素にフラット化する必要があることを示すブール値プロパティ。

falseに設定すると、Array.concatは配列をフラット化しません。

const alpha = ['a', 'b', 'c'];
const numeric = [1, 2, 3];

let alphaNumeric = alpha.concat(numeric);

// console.log(alphaNumeric);

numeric[Symbol.isConcatSpreadable] = false;

alphaNumeric = alpha.concat(numeric);

// alphaNumeric = [...alpha, ...numeric];
// the above line will output : ["a","b","c",1,2,3]

console.log(JSON.stringify(alphaNumeric)); // ["a","b","c",[1,2,3]]

ただし、spread動作が異なりますObjectsに関しては、 反復不可能

var obj = {'key1': 'value1'};
var array = [...obj]; // TypeError: obj is not iterable
var objCopy = {...obj}; // copy

提供されたオブジェクトから新しいオブジェクトに、自身の列挙可能なプロパティをコピーします。

スプレッド演算子の方が高速です。チェックしてください spread-into-array-vs-concat (Chrome 67以上)

そして、 つのドットがjavascriptをどのように変更したか いくつかのユースケースを確認してください。その中には 割り当ての破棄 (配列またはオブジェクト):

const arr = [1, 2, 3, 4, 5, 6, 7];

const [first, , third, ...rest] = arr;

console.log({ first, third, rest });

文字列を文字の配列に分割します:

console.log( [...'hello'] ) // [ "h", "e" , "l" , "l", "o" ]
2
Taki

与えられた例では、これら2つの間に違いはありません。連結には、spread演算子でconcatメソッドを使用できます。ただし、spread演算子の使用は、配列の連結に限定されません。

スプレッド構文を使用すると、配列式や文字列などの反復可能オブジェクトを展開できます。次のシナリオで使用できます。

  1. 配列を使用したスプレッド演算子

    • 配列の連結
    • 文字列から配列へ
    • 関数の引数としての配列。
  2. オブジェクトを使用したスプレッド演算子

    • オブジェクトの連結

これらすべての使用法のデモンストレーションを確認し、コードを実際に試すには、以下のリンク(codepen.io)をたどってください。

ES6-スプレッド演算子のデモンストレーション

/**
* Example-1: Showing How Spread Operator can be used to concat two or more     
arrays. 
*/
const americas = ['South America', 'North America'];

const eurasia = ['Europe', 'Asia'];

const world = [...americas, ...eurasia];

/**
* Example-2: How Spread Operator can be used for string to array.
*/
const iLiveIn = 'Asia';
const iLiveIntoArray = [...iLiveIn];

/**
* Example-3: Using Spread Operator to pass arguments to function
*/
const numbers = [1,4,5];

const add = function(n1,n2,n3){
return n1 + n2 + n3;
};

const addition = add(numbers[0],numbers[1],numbers[2]);
const additionUsingSpread = add(...numbers);

/**
* Example-4: Spread Operator, can be used to concat the array
*/

const personalDetails = {
  name: 'Ravi',
  age: '28',
  sex: 'male'
};

const professionalDetails = {
  occupation: 'Software Engineer',
  workExperience: '4 years'
};

const completeDetails = {...personalDetails, ...professionalDetails};
0
Ravi Upadhyay