のは、私が持っていると言うoptions
変数を、私はいくつかのデフォルト値を設定したいです。
これらの2つの選択肢の利点/欠点は何ですか?
オブジェクトスプレッドの使用
options = {...optionsDefault, ...options};
またはObject.assignを使用する
options = Object.assign({}, optionsDefault, options);
これは私が不思議に思ったコミットです。
のは、私が持っていると言うoptions
変数を、私はいくつかのデフォルト値を設定したいです。
これらの2つの選択肢の利点/欠点は何ですか?
オブジェクトスプレッドの使用
options = {...optionsDefault, ...options};
またはObject.assignを使用する
options = Object.assign({}, optionsDefault, options);
これは私が不思議に思ったコミットです。
回答:
これは必ずしも完全なものではありません。
options = {...optionsDefault, ...options};
ネイティブサポートのない環境で実行するコードを作成する場合、(ポリフィルを使用するのではなく)この構文をコンパイルするだけで済む場合があります。(例えば、Babelで。)
あまり冗長ではありません。
この回答が最初に書かれたとき、これは提案であり、標準化されていませんでした。プロポーザルを使用するときは、それを使用してコードを記述し、標準化に向けて移動しても標準化または変更されない場合にどうするかを検討してください。これは、ES2018で標準化されました。
動的ではなくリテラル。
Object.assign()
options = Object.assign({}, optionsDefault, options);
標準化されています。
動的。例:
var sources = [{a: "A"}, {b: "B"}, {c: "C"}];
options = Object.assign.apply(Object, [{}].concat(sources));
// or
options = Object.assign({}, ...sources);
これは私が不思議に思ったコミットです。
それはあなたが求めていることとは直接関係ありません。そのコードはを使用していませんでした。同じことObject.assign()
を行うユーザーコード(object-assign
)を使用していました。彼らはそのコードをBabelでコンパイルしている(そしてそれをWebpackにバンドルしている)ようです。これは、私が話していたものです。コンパイルできる構文です。彼らは明らかobject-assign
に彼らのビルドに入る依存関係として含める必要があることを好んだ。
Object.assign()
。それとも、手動で手動でターゲットに割り当てるオブジェクトと、自分の小道具の配列を反復処理し、それがさらに冗長作ることができます:P
参照オブジェクトのレスト/スプレッドは、ステージ4としてECMAScript 2018で最終決定されます。提案はこちらにあります。
ほとんどの場合、オブジェクトのリセットとスプレッドは同じように機能しますが、大きな違いは、spreadはプロパティを定義するのに対して、Object.assign()はそれらを設定することです。つまり、Object.assign()はセッターをトリガーします。
これ以外に、オブジェクトレスト/スプレッド1:1はObject.assign()にマップされ、配列(反復可能)スプレッドとは異なる動作をすることを覚えておく価値があります。たとえば、配列を拡散すると、ヌル値が拡散されます。ただし、オブジェクトスプレッドのnull値を使用すると、何も表示されずに暗黙的に広がります。
配列(反復可能)スプレッドの例
const x = [1, 2, null , 3];
const y = [...x, 4, 5];
const z = null;
console.log(y); // [1, 2, null, 3, 4, 5];
console.log([...z]); // TypeError
オブジェクトスプレッドの例
const x = null;
const y = {a: 1, b: 2};
const z = {...x, ...y};
console.log(z); //{a: 1, b: 2}
これはObject.assign()の動作と一致しており、どちらもエラーなしでnull値を暗黙的に除外します。
const x = null;
const y = {a: 1, b: 2};
const z = Object.assign({}, x, y);
console.log(z); //{a: 1, b: 2}
Object.assign
、セッターを使用することです。Object.assign({set a(v){this.b=v}, b:2}, {a:4}); // {b: 4}
対{...{set a(v){this.b=v}, b:2}, ...{a:4}}; // {a: 4, b: 2}
const x = {c: null};
。その場合、AFAIKでは、配列と同じように動作します//{a: 1, b: 2, c: null}
。
スプレッド演算子とObject.assign
現在の回答で言及されていないように見える大きな違いの1つは、スプレッド演算子がソースオブジェクトのプロトタイプをターゲットオブジェクトにコピーしないことです。オブジェクトにプロパティを追加し、そのインスタンスを変更したくない場合は、を使用する必要がありますObject.assign
。以下の例はこれを示しています:
const error = new Error();
error instanceof Error // true
const errorExtendedUsingSpread = {
...error,
...{
someValue: true
}
};
errorExtendedUsingSpread instanceof Error; // false
const errorExtendedUsingAssign = Object.assign(error, {
someValue: true
});
errorExtendedUsingAssign instanceof Error; // true
errorExtendedUsingAssign === error
、しかし、それerrorExtendedUsingSpread
は新しいオブジェクトです(そしてプロトタイプはコピーされませんでした)。
let target = Object.create(source); Object.assign(target, source);
他の人が述べたように、執筆の現時点でObject.assign()
は、ポリフィルが必要であり、オブジェクトの拡散に...
は、機能するためにいくつかのトランスパイル(およびおそらくポリフィル)が必要です。
このコードを考えてみましょう:
// Babel wont touch this really, it will simply fail if Object.assign() is not supported in browser.
const objAss = { message: 'Hello you!' };
const newObjAss = Object.assign(objAss, { dev: true });
console.log(newObjAss);
// Babel will transpile with use to a helper function that first attempts to use Object.assign() and then falls back.
const objSpread = { message: 'Hello you!' };
const newObjSpread = {...objSpread, dev: true };
console.log(newObjSpread);
これらは両方とも同じ出力を生成します。
以下は、BabelからES5への出力です。
var objAss = { message: 'Hello you!' };
var newObjAss = Object.assign(objAss, { dev: true });
console.log(newObjAss);
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var objSpread = { message: 'Hello you!' };
var newObjSpread = _extends({}, objSpread, { dev: true });
console.log(newObjSpread);
これは、これまでのところ私の理解です。Object.assign()
実際に標準化されていますが、オブジェクトの広がり...
はまだです。唯一の問題は、前者および将来的には後者のブラウザサポートです。
お役に立てれば。
{}
すると、不整合が修正されます。
オブジェクト展開演算子(...)はブラウザでは機能しません。これは、ES仕様の一部ではなく、単なる提案にすぎないためです。唯一のオプションは、Babel(または類似のもの)でコンパイルすることです。
ご覧のとおり、これはObject.assign({})に対する単なる構文上の砂糖です。
私が見る限り、これらは重要な違いです。
...
オブジェクトは標準化されていません...
オブジェクトを誤って変更しないように保護します...
Object.assignがなければ、ブラウザでObject.assignをポリフィルします...
同じアイデアを表現するために必要なコードが少ないObject.assign
。
ブラウザを介して、およびツールを介してエコシステムにおいて、「オブジェクトのマージの拡散」ES機能のステータスを要約したいと思います。
var x = { a: 1, b: 2 };
var y = { c: 3, d: 4, a: 5 };
var z = {...x, ...y};
console.log(z); // { a: 5, b: 2, c: 3, d: 4 }
繰り返しますが、このサンプルの執筆時点では、Chrome(60以降)、Firefox Developer Edition(Firefox 60のプレビュー)、およびNode(8.7以降)では、このサンプルは翻訳なしで機能します。
私はこれを2.5 年書いています元の質問から2.後にます。しかし、私は同じ質問をしました、そして、これはグーグルが私に送ったところです。私はロングテールを改善するSOの使命の奴隷です。
これは「配列分散」構文の拡張なので、グーグルで検索するのは非常に難しく、互換性の表で見つけるのは難しいと感じました。一番近いのはKangaxの「プロパティスプレッド」です。ですが、そのテストには同じ式の2つのスプレッドはありません(マージではありません)。また、プロポーザル/ドラフト/ブラウザのステータスページの名前はすべて「プロパティスプレッド」を使用していますが、「オブジェクトマージ」のスプレッド構文を使用するという提案の後にコミュニティが到達した「最初のプリンシパル」だったようです。(グーグルするのがなぜ難しいのかを説明しているかもしれません。)そこで、ここで私の発見を文書化して、他の人がこの特定の機能に関するリンクを表示、更新、およびコンパイルできるようにします。うまくいきますように。それが仕様とブラウザで着陸するというニュースを広めるのを手伝ってください。
最後に、この情報をコメントとして追加しましたが、著者の元の意図を壊さずに編集することはできませんでした。具体的には、@ RichardSchulteを修正する意図を失うことなく@ChillyPenguinのコメントを編集することはできません。しかし数年後、リチャードは正しいと判明しました(私の意見では)。だから私は代わりにこの答えを書いて、それが最終的に古い答えの牽引力を獲得することを願っています(結局、何年もかかるかもしれませんが、結局、それがロングテール効果のすべてです)。
注:Spreadは、Object.assignに関する単なる構文上の砂糖ではありません。彼らは舞台裏で大きく異なる動作をします。
Object.assignは新しいオブジェクトにセッターを適用しますが、Spreadは適用しません。さらに、オブジェクトは反復可能でなければなりません。
コピー オブジェクトの値が現時点で必要であり、その値にオブジェクトの他の所有者が行った変更を反映させたくない場合は、これを使用します。
オブジェクトの浅いコピーを作成するために使用して、常に不変のプロパティをコピーに設定します-変更可能なバージョンは不変のプロパティに渡すことができるため、コピーは常に不変オブジェクトを処理することを保証します
割り当て 割り当ては、コピーとは多少逆です。Assignは、値をコピーまたは保持するのではなく、インスタンス変数に直接値を割り当てるセッターを生成します。assignプロパティのゲッターを呼び出すと、実際のデータへの参照が返されます。
他の回答は古く、良い回答を得ることができませんでした。
以下の例はオブジェクトリテラルの例であり、両方が互いに補完し合う方法と、互いに補完できない方法(したがって、違い)を示しています。
var obj1 = { a: 1, b: { b1: 1, b2: 'b2value', b3: 'b3value' } };
// overwrite parts of b key
var obj2 = {
b: {
...obj1.b,
b1: 2
}
};
var res2 = Object.assign({}, obj1, obj2); // b2,b3 keys still exist
document.write('res2: ', JSON.stringify (res2), '<br>');
// Output:
// res2: {"a":1,"b":{"b1":2,"b2":"b2value","b3":"b3value"}} // NOTE: b2,b3 still exists
// overwrite whole of b key
var obj3 = {
b: {
b1: 2
}
};
var res3 = Object.assign({}, obj1, obj3); // b2,b3 keys are lost
document.write('res3: ', JSON.stringify (res3), '<br>');
// Output:
// res3: {"a":1,"b":{"b1":2}} // NOTE: b2,b3 values are lost
ここにもいくつかの小さな例があり、配列とオブジェクトも含まれています:https :
//developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
これは現在ES6の一部であり、標準化されており、MDNでも文書化されています。 ます。https //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator
使用するのは非常に便利で、オブジェクトの構造化と並んで非常に理にかなっています。
上記の残りの利点の1つは、Object.assign()の動的な機能ですが、これは、リテラルオブジェクト内に配列を分散するのと同じくらい簡単です。コンパイルされたバベル出力では、Object.assign()で示されているものをそのまま使用します
したがって、オブジェクトスプレッドは標準化され、広く使用されており(react、reduxなどを参照)、使いやすく、Object.assign()のすべての機能を備えているため、正しい答えはオブジェクトスプレッドを使用することです。
Object.assignを使用する必要がある場合は、この簡単な例を追加します。
class SomeClass {
constructor() {
this.someValue = 'some value';
}
someMethod() {
console.log('some action');
}
}
const objectAssign = Object.assign(new SomeClass(), {});
objectAssign.someValue; // ok
objectAssign.someMethod(); // ok
const spread = {...new SomeClass()};
spread.someValue; // ok
spread.someMethod(); // there is no methods of SomeClass!
JavaScriptを使用すると、はっきりしない場合があります。TypeScriptを使用すると、クラスのインスタンスを作成する方が簡単です。
const spread: SomeClass = {...new SomeClass()} // Error