
在ES6中新增的对象的扩展方法中,该方法可以实现复制一个或者多个对象到target对象中。
函数原型
关于该函数的定义是:
第一个参数为目标对象,第二个是源对象(可以是多个对象)。通过调用爱函数可以复制所有可被枚举的自有属性到目标对象中。1
Object.assign(target,...source);
关于该函数,强调三点:
- 可以被枚举的属性;
- 自有属性;
- string或Symbol类型是可以直接分配的;
如果只有一个参数,那么Object.assign将会直接返回该参数。如果该参数不是对象,则转换为对象后返回。
1 | console.log(typeof(Object.assign(2))); //"object" |
由于undefined和null无法被包装成为对象,所以不能作为首参数使用。但是可以作为源对象使用。
其他基本类型的值(数值、字符串和布尔值)不在首参数时,不会报错。但是只有字符串会以数组形式复制进入目标对象,其他的基本类型值不会产生这样的效果。
1 | var v1 = 'abc'; |
因为只有字符串类型的包装对象可以产生可枚举属性,布尔值与数值的包装对象无法经过包装对象生成可枚举属性。
1 | Object(true) // {[[PrimitiveValue]]: true} |
布尔值、数值的转换为对应的包装对象后,原始值都在包装对象的内部属性[[PrimitiveValue]]中,该属性不会被Object.assign拷贝。只有字符串的包装对象会产生可枚举的实义属性。
对于属性名为Symbol止的属性,也可以被Object.assign拷贝。1
Object.assign({ a: 'b' }, { [Symbol('c')]: 'd' }) // { a: 'b', Symbol(c): 'd' }
Object.assign拷贝的属性是有限制的,不可以复制不可枚举属性,只会拷贝源对象的自身属性(不拷贝继承属性)。
注意:通过Object.defineProperty定义的对象属性,默认是不可枚举的,即enumerable:false。对于可枚举的对象,可以直接使用Object.keys()获得,或者使用for-in循环遍历。
对于不可枚举的属性,使用Object.assign复制时会被直接忽略。
1 | var obj = Object.create({ foo: 1 }, { // foo is an inherit property. |
只可浅复制
复制对象
如果源对象某个属性值是对象,那么目标对象复制得到的是这个对象的引用。
1 | var objC = { |
对于复制源对象的任何变化,都会反映到目标对象中。对于嵌套的对象,一旦遇到同名属性Object.assign的处理方法是直接替换,而不是添加。所以在以上的代码中,objD.a.b的属性值发生了变化。
复制数组
Object.assign可以处理数组,但是会把数组视为对象。1
Object.assign([1,2,3],[4,5]);//[4,5,3]
这是因为数组视为属性名为0,1,2的对象。
如果一定要使用它来实现深复制,就只能借助其他的函数库,比如:deep-merge。
常见用途
1. 为对象添加属性
1 | class Point { |
通过该方法可以将x属性和y属性添加到Point类的对象实例。
2. 为对象添加方法
1 | Object.assign(SomeClass.prototype,{ |
3. 克隆对象
1 | function clone(orign){ |
采用第一种方法只能复制原始对象自身的值,不能复制继承的值。如果要保持继承链,可以使用第二种方法,getPropertyOf可以获取到原型链上的属性,包括不可枚举的属性。
4. 合并对个对象
将多个对象合并到某个对象1
2
3
4
5
6let objR = {
b : 2,
c : [12,9,3,3]
};
const merge = (target,...source) => Object.assign(target,...source);
console.log(merge(objR,{a:9,b:"oi"}));
如果希望合并后返回一个新对象,可以改写上面的函数,对一个空对象合并。1
2
3
4
5
6let objR = {
b : 2,
c : [12,9,3,3]
};
const merge = (...source) => Object.assign({},...source);
console.log(merge(objR,{a:9,b:"oi"}));
5. 为属性指定默认值
1 | const DEFAULTS = { |
DEFAULTS是默认值,options是用户提供的参数,Object.assign将两个对象合并为新对象,如果具有同名属性,那么options的属性会覆盖默认属性值。
注意:由于浅复制的问题,DEFAULTS对象和options对象的所有属性值最好都是简单类型。不要指向另一个对象,否则默认属性值可能会失效。
1 | const DEFAULTS = { |
此时得到的options只有url: {port: 8000},url的host不存在了。