ES6中Object.assign方法使用詳解
1、前言
首先了解下Object.assign()是什么。我們先看看ES6官方文檔是怎么介紹的?
Object.assign() 方法用于將所有可枚舉屬性的值從一個(gè)或多個(gè)源對象復(fù)制到目標(biāo)對象。它將返回目標(biāo)對象。
注意:Object.assign() 方法至少需要兩個(gè)對象作為參數(shù),第一個(gè)參數(shù)是目標(biāo)對象,后面的參數(shù)都是源對象。
2、語法
語法:
Object.assign(target, ...sources)
參數(shù):target
—>目標(biāo)對象
source
—>源對象
返回值:target
,即目標(biāo)對象
3、基本用法
3.1 目標(biāo)對象和源對象無重名屬性
var target = { name: '張三', age: 18 } var source = { money: '10000' } var result = Object.assign(target, source) console.log(result) console.log(target);
運(yùn)行結(jié)果如下:
我們可以看到source上的state屬性合并到了target對象上。如果只是想將兩個(gè)或多個(gè)對象的屬性合并到一起,不改變原有對象的屬性,可以用一個(gè)空的對象作為target對象。像下面這樣:
var target = { name: '張三', age: 18 } var source = { money: '10000' } var result = Object.assign({}, target, source) console.log(result);
運(yùn)行結(jié)果如下:
3.2 目標(biāo)對象和源對象有重名屬性
var target = { name: '張三', age: 18 } var source = { money: '10000', age: 28 } var result = Object.assign(target, source) console.log(target)
運(yùn)行結(jié)果如下:
可以看到如果有同名屬性的話,后面的屬性值會覆蓋前面的屬性值。
3.3 有多個(gè)源對象
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)
運(yùn)行結(jié)果如下:
可以看到有多個(gè)源對象情況也是和一個(gè)源對象一樣的。沒有同名的屬性會直接復(fù)制到目標(biāo)對象上,同名的屬性后面的屬性值會覆蓋前面的同名屬性值。
3.4 其他情況
3.4.1 只有一個(gè)參數(shù)時(shí),Object.assign會直接返回該參數(shù)
var obj = { a: 1 } console.log(Object.assign(obj)) console.log(Object.assign(obj) === obj);
運(yùn)行結(jié)果如下:
3.4.2 如果該參數(shù)不是對象,則會先轉(zhuǎn)成對象,然后返回
typeof Object.assign(2) // object
3.4.3 出現(xiàn)undefined和null情況
由于undefined和null無法轉(zhuǎn)成對象,所以如果將它們作為參數(shù),就會報(bào)錯(cuò)。
Object.assign(undefined) Object.assign(null)
運(yùn)行結(jié)果如下:
注意:如果非對象參數(shù)出現(xiàn)在源對象的位置(即非首參數(shù)),那么處理規(guī)則將有所不同。首先,這些參數(shù)都會被轉(zhuǎn)成對象,如果無法轉(zhuǎn)成對象便會跳過。這意味著,如果undefined和null不在首參數(shù)便不會報(bào)錯(cuò)。
let obj = { a: 1 } Object.assign(obj, undefined) === obj // true Object.assign(obj, null) === obj // true
3.4.4 其他類型的值
其他類型的值(即數(shù)值、字符串、布爾值)不在首參數(shù)也不會出錯(cuò)。但是,除了字符串會以數(shù)組形式賦值到目標(biāo)對象,其他值都不會產(chǎn)生效果。
var v1 = 'abc' var v2 = true var v3 = 10 var obj = Object.assign({}, v1, v2, v3) console.log(obj);
運(yùn)行結(jié)果如下:
上面的代碼中,v1, v2, v3分別是字符串、布爾值和數(shù)值,結(jié)果只有字符串合入目標(biāo)對象(以字符數(shù)組的形式),數(shù)值和布爾值都會被忽略。這是因?yàn)橹挥凶址陌b對象會產(chǎn)生枚舉屬性。
console.log(Object(true)) console.log(Object(10)) console.log(Object('abc'));
運(yùn)行結(jié)果如下:
上面的代碼中,布爾值、數(shù)值、字符串分別轉(zhuǎn)成對應(yīng)的包裝對象,可以看到它們的原始值都在包裝對象的內(nèi)部屬性[[PrimitiveValue]]上面,這個(gè)屬性是不會被Object.assign() 復(fù)制的。只有字符串的包裝會產(chǎn)生可枚舉的實(shí)義屬性,那些屬性則會被拷貝。
Object.assign 復(fù)制的屬性是有限制的,只復(fù)制源對象的自身屬性(不復(fù)制繼承屬性),也不復(fù)制不可枚舉的屬性(enumerable: false)。
let obj = Object.assign({ b: 'c' }, Object.defineProperty({}, 'invisible', { enumerable: false, value: 'hello world' }) ) console.log(obj);
運(yùn)行結(jié)果如下:
上面的代碼中,Object.assign要復(fù)制的對象只有一個(gè)不可枚舉對屬性invisible,這個(gè)屬性并沒有被復(fù)制進(jìn)去。
屬性名為Symbol值的屬性也會被Object.assign復(fù)制。
let obj = Object.assign({ b: 'c' }, { [Symbol('c')]: 'd' }) console.log(obj);
運(yùn)行結(jié)果如下:
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);
運(yùn)行結(jié)果如下:
上面的方法通過assign方法將x屬性和y屬性添加到了Point類的對象實(shí)例中。
4.2 為對象添加方法
Object.assign(SomeClass.prototype, { someMethod (argl, arg2) { ... }, anotherMethod () { ... }, }) 等同于下面的寫法 SomeClass.prototype.someMethod = function (argl, arg2) { ... } SomeClass.prototype.anotherMethod = function () { ... }
上面的代碼使用了對象屬性的簡潔表示法,直接將兩個(gè)函數(shù)放在大括號中,再使用assign方法添加到SomeClass.prototype中。
4.3 克隆對象
function clone (origin) { return Object.assign({}, origin) }
上面的代碼將原始對象復(fù)制到一個(gè)空對象中,就得到了原始對象的克隆。
不過,采用這種方法只能克隆原始對象自身的值,不能克隆它繼承的值。如果想要保持繼承鏈,可以采用下面這段代碼。
function clone (origin) { let originProto = Object.getPrototypeOf(origin) return Object.assign(Object.create(originProto), origin) }
4.4 合并多個(gè)對象
- 將多個(gè)對象合并到某個(gè)對象
const merge = (target, ...sources) => Object.assign(target, ...sources);
- 如果希望合并后返回一個(gè)新對象,可以改寫上面的函數(shù),對一個(gè)空對象合并。
const merge = (...sources) => Object.assign({}, ...sources);
4.4 為屬性指定默認(rèn)值
const DEFAULTS = { logLevel: 0, outputForrnat: 'html' } function processContent (options) { options = Object.assign({}, DEFAULTS, options) console.log(options) }
上面的代碼中,DEFAULTS 對象是默認(rèn)值,options對象是用戶提供的參數(shù)。
Object.assign方法將DEFAULTS和options合并成一個(gè)新對象,如果兩者有同名屬性,則options的屬性值會覆蓋DEFAULTS 屬性值。
注意:由于存在深復(fù)制的問題,DEFAULTS對象和options對象的所有屬性
的值都只能是簡單類型,而不能指向另一個(gè)對象,否則將導(dǎo)致DEFAULTS對象的該屬性不起作用。
const DEFAULTS = { url: { host: 'example.corn', port: 7070 } } processContent ( { url: {port : 8000} } ) //{ // url: {port: 8000) //}
上面的代碼原意是將url.port改成8000,而url.host保持不變。實(shí)際結(jié)果卻是options.url覆蓋了DEFAULTS.url,所以url.host就不復(fù)存在了。
5、注意事項(xiàng)
1、Object.assign 方法只會拷貝源對象自身的并且可枚舉的屬性到目標(biāo)對象,繼承屬性和不可枚舉屬性是不能拷貝的;
2、針對深拷貝,需要使用其他辦法,因?yàn)?Object.assign()拷貝的是屬性值。假如源對象的屬性值是一個(gè)對象的引用,那么它也只指向那個(gè)引用;
3、目標(biāo)對象自身也會改變;
4、異常會打斷后續(xù)拷貝任務(wù);
5、Object.assign可以用來處理數(shù)組,但是會把數(shù)組視為對象來處理。
let obj = Object.assign([1, 2, 3], [4, 5]) console.log(obj); // [4, 5, 3]
上面的代碼中, Object.assign把數(shù)組視為屬性名為0、1、2的對象,因此目標(biāo)數(shù)組的0號屬性覆蓋了0號屬性1。
6、兼容性
目前IE瀏覽器不兼容Object.assign(),如果需要兼容IE的話最好不要直接使用這個(gè)方法。
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')
可以看到兩者得到的結(jié)果是一樣的。
總結(jié)
到此這篇關(guān)于ES6中Object.assign方法使用的文章就介紹到這了,更多相關(guān)ES6 Object.assign方法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
IE和Firefox下javascript的兼容寫法小結(jié)
學(xué)習(xí)js的朋友必須要知道或了解的知識2008-12-12JavaScript模擬實(shí)現(xiàn)繼承的方法
這篇文章主要介紹了JavaScript模擬實(shí)現(xiàn)繼承的方法,實(shí)例分析了javascript類的操作與模擬實(shí)現(xiàn)繼承的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-03-03