Object.assign()
方法用於對象的合併,將全部自身的(非繼承的)可枚舉屬性的值從一個或多個源對象拷貝到目標對象。返回目標對象。目標對象自身也會改變。es6
Object.assign(target, ...sources)
target
: 目標對象。sources
: 源對象。只拷貝源對象的自身屬性(不拷貝繼承屬性),也不拷貝不可枚舉的屬性(enumerable: false
)。數組
Object.assign({b: 'c'}, Object.defineProperty({}, 'invisible', { enumerable: false, value: 'hello' }) ) // { b: 'c' }
若是隻有一個參數,Object.assign()
會直接返回該參數。函數
let obj = {a: 1}; Object.assign(obj) === obj // true
若是該參數不是對象,則會先轉成對象,而後返回。this
typeof Object.assign(2) // "object"
因爲 undefined
和 null
沒法轉成對象,因此若是它們做爲參數,就會報錯。prototype
Object.assign(undefined) // 報錯 Object.assign(null) // 報錯
非對象參數都會轉成對象,若是沒法轉成對象,就會跳過,不會報錯。code
若是非對象參數爲 undefined
和 null
,就會跳過,不會報錯,返回的依舊是目標對象參數。對象
let obj = {a: 1}; Object.assign(obj, undefined) === obj // true Object.assign(obj, null) === obj // true
若是非對象參數爲其餘類型的值(即數值、字符串和布爾值),也不會報錯。可是,除了字符串會以數組形式拷貝入目標對象,其餘值都不會產生效果。這是由於只有字符串的包裝對象,會產生可枚舉屬性。繼承
let v1 = 'abc'; let v2 = true; let v3 = 10; let obj = Object.assign({}, v1, v2, v3); console.log(obj) // { "0": "a", "1": "b", "2": "c" }
null
或 undefined
的屬性會正常合併Object.assign()
不會跳過那些屬性值爲 null
或 undefined
的源對象。遞歸
var o1 = { a: null, b: 1}; var o2 = { c: undefined }; var obj = Object.assign({}, o1, o2); obj // {a: null, b: 1, c: undefined}
若是目標對象與源對象中的屬性具備相同的鍵,則目標對象屬性將被源中的屬性覆蓋。後來的源的屬性將相似地覆蓋早先的屬性。ip
var o1 = { a: 1, b: 1, c: 1 }; var o2 = { b: 2, c: 2 }; var o3 = { c: 3 }; var obj = Object.assign({}, o1, o2, o3); obj // { a: 1, b: 2, c: 3 }
Object.assign()
方法實行的是淺拷貝,而不是深拷貝。拷貝的是屬性值。假如源對象的屬性值是一個指向對象的引用,它也只拷貝那個引用值。
var obj1 = { a: 0 , b: { c: 0 } }; var obj2 = Object.assign({}, obj1); obj2 // { a: 0, b: { c: 0 } }; obj2.b.c = 3; obj1 // { a: 0, b: { c: 3 } }; obj2 // { a: 0, b: { c: 3 } };
Object.assign()
能夠用來處理數組,可是會把數組視爲鍵值爲數組下標的對象來合併,然而最終的返回形式也是數組。
Object.assign([1, 2, 3], [4, 5]) // [4, 5, 3] Object.assign({0:1,1:2,2:3},{0:4,1:5}) // {0: 4, 1: 5, 2: 3}
Object.assign()
若是遇到存取器定義的屬性,會只拷貝值。
var obj = { foo: 1, get bar() { return 2; } }; var copy = Object.assign({}, obj); copy // { foo: 1, bar: 2 }
所以必須使用 Object.getOwnPropertyDescriptors()
方法配合 Object.defineProperties()
方法,就能夠實現正確拷貝。但僅限於可拷貝 getter
和 setter
,對於屬性的引用類型仍是屬於淺拷貝。
var obj = { foo: { a : 0 }, get bar() { return 2; } }; var target = Object.defineProperties({}, Object.getOwnPropertyDescriptors(obj) ); Object.getOwnPropertyDescriptor(target, 'bar') // { get : ƒ bar(), set : undefined, enumerable : true, configurable : true } obj.foo.a = 6 target.foo.a // 6
class Point { constructor(x, y) { Object.assign(this, {x, y}); } }
上面方法經過 Object.assign()
方法,將 x
屬性和 y
屬性添加到 Point
類的對象實例。
Object.assign(SomeClass.prototype, { someMethod(arg1, arg2) { ··· }, anotherMethod() { ··· } }); // 等同於下面的寫法 SomeClass.prototype.someMethod = function (arg1, arg2) { ··· }; SomeClass.prototype.anotherMethod = function () { ··· };
let obj = {a:5}; function clone(origin) { return Object.assign({}, origin); } let aaa = clone(obj); // {a:5}
不過,採用這種方法克隆,只能克隆原始對象自身的值,不能克隆它繼承的值。若是想要保持繼承鏈,能夠採用下面的代碼。
function clone(origin) { let originProto = Object.getPrototypeOf(origin); return Object.assign(Object.create(originProto), origin); }
let merge = (target, ...sources) => Object.assign(target, ...sources);
若是但願合併後返回一個新對象,能夠改寫上面函數,對一個空對象合併。
let merge = (...sources) => Object.assign({}, ...sources);
const DEFAULTS = { a: 0, b: 'ccc' }; function copy(options) { options = Object.assign({}, DEFAULTS, options); // ... }
注意,因爲存在淺拷貝的問題,DEFAULTS對象和options對象的全部屬性的值,最好都是簡單類型,不要指向另外一個對象。不然,DEFAULTS對象的該屬性極可能不起做用。
參考連接:Object.assign()
var obj1 = { a: 0 , b: { c: 0}}; var obj2 = JSON.parse(JSON.stringify(obj1)); obj1.b.c = 4; obj2 // { a: 0, b: { c: 0}}
但因爲 JSON
的侷限性,該方法也不是萬能的。好比,若是對象的屬性是 undefined
、函數、symbol
或 XML
對象,該屬性會被 JSON.stringify()
過濾掉,致使拷貝時會缺乏屬性。
let obj = { name:'dora', sayHello:function(){ console.log('Hello World'); } } let cloneObj = JSON.parse(JSON.stringify(obj)); console.log(cloneObj); // {name: "dora"}
function deepClone(source){ let targetObj = source.constructor === Array ? [] : {}; for(let keys in source){ if(source.hasOwnProperty(keys)){ if(source[keys] && typeof source[keys] === 'object'){ targetObj[keys] = source[keys].constructor === Array ? [] : {}; targetObj[keys] = deepClone(source[keys]); }else{ targetObj[keys] = source[keys]; } } } return targetObj; } let obj = { a: { b: 1, c: 2 }, sayHello: function(){ console.log('Hello World'); } } let cloneObj = deepClone(obj); obj.a.b = 4 obj // {a:{b: 4, c: 2},sayHello:ƒ ()} cloneObj // {a:{b: 1, c: 2},sayHello:ƒ ()}