ES6: Object.assignメソッドの詳細説明
1 はじめに
まず Object.assign() が何であるかを理解します。ES6 の公式ドキュメントでどのように紹介されているか見てみましょう。
Object.assign() メソッドは、すべての列挙可能なプロパティの値を 1 つ以上のソース オブジェクトからターゲット オブジェクトにコピーするために使用されます。ターゲットオブジェクトを返します。
注: Object.assign() メソッドにはパラメータとして少なくとも 2 つのオブジェクトが必要です。最初のパラメータはターゲット オブジェクト、次のパラメータはソース オブジェクトです。
2. 文法
文法:
Object.assign(target, ...sources)
パラメータ:
target
—> ターゲットオブジェクト
source
—> ソースオブジェクト
戻り値: target
、ターゲットオブジェクト
3. 基本的な使い方
3.1 ターゲット オブジェクトとソース オブジェクトに同じ名前の属性がない
var target = {
name: '张三', age: 18 }
var source = {
money: '10000' }
var result = Object.assign(target, source)
console.log(result)
console.log(target);
実行結果は次のとおりです。
ソースの state 属性がターゲット オブジェクトにマージされていることがわかります。元のオブジェクトの属性を変更せずに、2 つ以上のオブジェクトの属性を結合するだけの場合は、空のオブジェクトをターゲット オブジェクトとして使用できます。このような:
var target = {
name: '张三', age: 18 }
var source = {
money: '10000' }
var result = Object.assign({
}, target, source)
console.log(result);
操作の結果は次のようになります。
3.2 ターゲット オブジェクトとソース オブジェクトに同じ名前の属性がある
var target = {
name: '张三', age: 18 }
var source = {
money: '10000', age: 28 }
var result = Object.assign(target, source)
console.log(target)
実行結果は次のとおりです。
同じ名前の属性が存在する場合、後の属性値が前の属性値を上書きすることがわかります。
3.3 複数のソースオブジェクトがある
var target = {
name: '张三', age: 18 }
var source1 = {
money: '10000', age: 28 }
var source2 = {
mood: 'happy', age: 25 }
var result = Object.assign(target, source1, source2)
console.log(target)
実行結果は以下のとおりです。
複数のソースオブジェクトの状況は、1 つのソースオブジェクトの状況と同じであることがわかります。同じ名前のない属性はターゲット オブジェクトに直接コピーされ、同じ名前の属性の後の属性値は、同じ名前の前の属性値を上書きします。
3.4 その他の状況
3.4.1 パラメータが 1 つだけの場合、Object.assign はパラメータを直接返します
var obj = {
a: 1 }
console.log(Object.assign(obj))
console.log(Object.assign(obj) === obj);
操作の結果は次のようになります。
3.4.2 パラメータがオブジェクトではない場合、まずオブジェクトに変換されてから返されます。
typeof Object.assign(2) // object
3.4.3 未定義とnullが表示される
unfineed や null はオブジェクトに変換できないため、パラメータとして使用するとエラーが報告されます。
Object.assign(undefined)
Object.assign(null)
操作の結果は次のようになります。
注: 非オブジェクト パラメータがソース オブジェクトの代わりに表示される場合 (つまり、最初のパラメータではない場合)、処理ルールは異なります。まず、これらのパラメータはオブジェクトに変換されますが、オブジェクトに変換できない場合はスキップされます。これは、最初のパラメータに未定義と null が含まれていない場合、エラーは報告されないことを意味します。
let obj = {
a: 1
}
Object.assign(obj, undefined) === obj // true
Object.assign(obj, null) === obj // true
3.4.4 他の型の値
他の型の値 (つまり、数値、文字列、ブール値) は、エラーなしに最初のパラメーターに含まれません。ただし、他の値は、文字列が配列の形式でターゲット オブジェクトに割り当てられることを除き、何の効果もありません。
var v1 = 'abc'
var v2 = true
var v3 = 10
var obj = Object.assign({
}, v1, v2, v3)
console.log(obj);
操作の結果は次のようになります。
上記のコードでは、v1、v2、v3 はそれぞれ文字列、ブール値、数値となっており、結果として文字列のみが対象オブジェクト(文字配列形式)にマージされ、数値はマージされます。ブール値は無視されます。これは、文字列ラッパー オブジェクトのみが enum プロパティを生成するためです。
console.log(Object(true))
console.log(Object(10))
console.log(Object('abc'));
実行結果は以下の通りです:
上記のコードでは、ブール値、数値、文字列がそれぞれ対応するパッケージング オブジェクトに変換されており、元の値はすべてパッケージの内部プロパティ [[PrimitiveValue]] にあることがわかります。パッケージ化オブジェクト。このプロパティは Object.assign() によってコピーされません。文字列のラップのみによって列挙可能なリテラル プロパティが生成され、それらのプロパティがコピーされます。
Object.assign によってコピーされるプロパティは制限されており、ソース オブジェクトの独自のプロパティのみがコピーされ (継承されたプロパティはコピーされません)、列挙不可能なプロパティ (列挙可能: false) はコピーされません。
let obj = Object.assign({
b: 'c' },
Object.defineProperty({
}, 'invisible', {
enumerable: false,
value: 'hello world'
})
)
console.log(obj);
実行結果は次のとおりです。
上記のコードでは、Object.assign によってコピーされるオブジェクトには、目に見えない列挙不可能なペア プロパティが 1 つだけあり、このプロパティはコピーされていません。
プロパティ名が Symbol 値であるプロパティも、Object.assign によってコピーされます。
let obj = Object.assign({
b: 'c' }, {
[Symbol('c')]: 'd' })
console.log(obj);
操作の結果は次のようになります。
4. 高度な使い方
4.1 オブジェクトにプロパティを追加する
class Point {
constructor(x, y) {
Object.assign(this, {
x, y })
console.log(this)
}
}
const p1 = new Point('12', '23')
console.log(p1);
操作の結果は次のようになります。
上記のメソッドは、assign メソッドを通じて Point クラスのオブジェクト インスタンスに x 属性と y 属性を追加します。
4.2 オブジェクトへのメソッドの追加
Object.assign(SomeClass.prototype, {
someMethod (argl, arg2) {
...
},
anotherMethod () {
...
},
})
等同于下面的写法
SomeClass.prototype.someMethod = function (argl, arg2) {
...
}
SomeClass.prototype.anotherMethod = function () {
...
}
上記のコードは、オブジェクト プロパティの簡潔な表現を使用し、2 つの関数を直接中かっこで囲み、次に assign メソッドを使用してそれらを SomeClass.prototype に追加します。
4.3 オブジェクトのクローン作成
function clone (origin) {
return Object.assign({
}, origin)
}
上記のコードは、元のオブジェクトを空のオブジェクトにコピーし、元のオブジェクトのクローンを取得します。
ただし、このメソッドを使用すると、元のオブジェクト自体の値のみがクローン化され、継承された値はクローン化されません。継承チェーンを保持したい場合は、次のコードを使用できます。
function clone (origin) {
let originProto = Object.getPrototypeOf(origin)
return Object.assign(Object.create(originProto), origin)
}
4.4 複数のオブジェクトの結合
- 複数のオブジェクトを 1 つのオブジェクトに結合する
const merge = (target, ...sources) => Object.assign(target, ...sources);
- マージ後に新しいオブジェクトを返したい場合は、空のオブジェクトをマージするように上記の関数を書き直すことができます。
const merge = (...sources) => Object.assign({
}, ...sources);
4.4 プロパティのデフォルト値の指定
const DEFAULTS = {
logLevel: 0,
outputForrnat: 'html'
}
function processContent (options) {
options = Object.assign({
}, DEFAULTS, options)
console.log(options)
}
上記のコードでは、DEFAULTS オブジェクトはデフォルト値であり、options オブジェクトはユーザーが指定したパラメータです。
Object.assign メソッドは、DEFAULTS とオプションを新しいオブジェクトに結合します。両方に同じ名前のプロパティがある場合、オプションのプロパティ値が DEFAULTS のプロパティ値をオーバーライドします。
注: ディープ コピーの問題により、
DEFAULTS オブジェクトとオプション オブジェクトのすべてのプロパティの値は単純型のみにすることができ、別のオブジェクトを指すことはできません。そうでない場合、DEFAULTS オブジェクトのプロパティは機能しません。
const DEFAULTS = {
url: {
host: 'example.corn',
port: 7070
}
}
processContent ( {
url: {
port : 8000} } )
//{
// url: {port: 8000)
//}
上記のコードの本来の目的は、url.host を変更せずに、url.port を 8000 に変更することです。実際の結果は、options.url が DEFAULTS.url をオーバーライドするため、url.host は存在しなくなります。
5. 注意事項
1. Object.assign メソッドは、ソース オブジェクト自体の列挙可能な属性のみをターゲット オブジェクトにコピーします。継承された属性と列挙不可能な属性はコピーできません。
2. Object.assign() は属性値をコピーするため、ディープ コピーの場合は他のメソッドを使用する必要があります。ソース オブジェクトの属性値がオブジェクトへの参照である場合、それはその参照のみを指します。
3. 対象者そのものが変化する。
4. 異常により後続のコピー タスクが中断されます。
5. Object.assign は配列の処理に使用できますが、配列をオブジェクトとして扱います。
let obj = Object.assign([1, 2, 3], [4, 5])
console.log(obj); // [4, 5, 3]
上記のコードでは、Object.assign は配列を属性名 0、1、2 を持つオブジェクトとして扱うため、ターゲット配列の属性 0 は属性 1 の 0 をオーバーライドします。
6. 互換性
現在、IE ブラウザは Object.assign() と互換性がありません。IE と互換性を持たせる必要がある場合は、このメソッドを直接使用しないことをお勧めします。
7. $.extend() との比較
var target = {
name: '张三', age: 18 }
var source1 = {
state: 'single', age: 22 }
var source2 = {
mood: 'happy', age: 25 }
var result = Object.assign(target, source1, source2)
console.log(target, 'assign')
var targetObj = {
name: '张三', age: 18 }
var sourceObj1 = {
state: 'single', age: 22 }
var sourceObj2 = {
mood: 'happy', age: 25 }
var result = $.extend(targetObj, sourceObj1, sourceObj2)
console.log(targetObj, 'extend')
両方で得られる結果は同じであることがわかります。