最近再写ES6的文章时候发现本身对Object.assign()方法不太了解,以前也没有接触过因此就就查阅了相关的资料,为了本身之后肯能会用到以及对知识进行巩固,因此在这里记录下本身学习的点点滴滴,毕竟好记性不如然笔筒,废话很少说,直接上干货。javascript
官方解释:Object.assign方法用于将全部可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。html
语法:Object.assign(target,...sources)
java
参数:函数
target:目标对象学习
sources:源对象spa
返回值:目标对象code
描述:若是目标对象中的属性具备相同的键,则属性将被源对象中的属性覆盖,后面的源对象的属性将覆盖前面的源对象的属性htm
Object.assign
方法只会拷贝源对象自身的而且可枚举的属性到目标对象。该方法使用源对象的[[Get]]
和目标对象的[[Set]]
,因此它会调用相关 getter 和 setter。所以,它分配属性,而不单单是复制或定义新的属性。若是合并源包含getter,这可能使其不适合将新属性合并到原型中。为了将属性定义(包括其可枚举性)复制到原型,应使用Object.getOwnPropertyDescriptor()
和Object.defineProperty()
。对象
注意:blog
TypeError
,若是在引起错误以前添加了任何属性,则能够更改target
对象String
类型和 Symbol
类型的属性都会被拷贝<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>复制一个对象</title> </head> <body> <script type="text/javascript"> const obj={ a:1, eat:function(){ console.log('吃东西') } } const copy=Object.assign({},obj); console.log(copy.a);//1 copy.eat();//吃东西 copy.a=10; console.log(copy.a);//10 console.log(obj.a);//1 </script> </body> </html>
咱们首先定义了一个obj对象,而后使用Object.assign方法拷贝了obj这个对象对copy中,发现copy中具备obj的属性和方法,当咱们修改copy中a的值的时候发现obj中a的值没有发生改变,由此能够证实Object.assign实现的是深拷贝,从新在内存中开辟新的空间,而不是拷贝原来对象的地址。
针对深拷贝,须要使用其余办法,由于 Object.assign()
拷贝的是属性值。假如源对象的属性值是一个对象的引用,那么它也只指向那个引用
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>实现深拷贝</title> </head> <body> <script type="text/javascript"> let obj1={a:0,b:{c:0}}; let obj2=Object.assign({},obj1); console.log(JSON.stringify(obj2));//{"a":0,"b":{"c":0}} obj1.a=1; console.log(JSON.stringify(obj1));//{"a":0,"b":{"c":0}} console.log(JSON.stringify(obj2));//{"a":0,"b":{"c":0}} obj2.a=2; console.log(JSON.stringify(obj1));//{"a":0,"b":{"c":0}} console.log(JSON.stringify(obj2));//{"a":0,"b":{"c":0}} obj2.a=3; console.log(JSON.stringify(obj1));//{"a":0,"b":{"c":0}} console.log(JSON.stringify(obj2));//{"a":0,"b":{"c":0}} //深拷贝 obj1={a:0,b:{c:0}} let obj3=JSON.parse(JSON.stringify(obj1)); obj1.a=4; obj1.b.c=4; console.log(JSON.stringify(obj3));//{"a":0,"b":{"c":0}} </script> </body> </html>
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>合并对象</title> </head> <body> <script type="text/javascript"> const o1={a:1}; const o2={b:2}; const o3={c:3}; const obj=Object.assign(o1,o2,o3); console.log(obj);//{a:1,b:2,c:3} console.log(o1);//{a:1,b:2,c:3} console.log(o2);//{b:2} console.log(o3);//{c:3} </script> </body> </html>
在这里咱们须要注意的是目标对象自身也会改变,即示例中的o1
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>合并具备相同属性的对象</title> </head> <body> <script type="text/javascript"> const o1={a:1,b:1,c:1}; const o2={b:2,c:2}; const o3={c:3}; const obj=Object.assign(o1,o2,o3); console.log(obj);//1,2,3 console.log(o1);//1,2,3 </script> </body> </html>
若是目标对象中的属性具备相同的键,则属性将被源对象中的属性覆盖,后面的源对象的属性将覆盖前面的源对象的属性,这句话已经解释的很清楚了,咱们看到o1中都有a,b,c三个属性,o2中具备b,c两个属性,o3中具备c一个属性,当合并的时候发现目标对象具备相同的键,因此被覆盖了。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>拷贝symbol类型的属性</title> </head> <body> <script type="text/javascript"> const o1={a:1}; const o2={[Symbol('foo')]:2}; const obj=Object.assign({},o1,o2); console.log(obj);// { a : 1, [Symbol("foo")]: 2 } console.log(Object.getOwnPropertySymbols(obj));// [Symbol(foo)] </script> </body> </html>
在这里的话,可能对symbol会有些陌生,不过没关系后续的博客中我会讲到,如今的话我能够告诉你这也是一种用来定义类型的类型
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>继承属性和不可枚举属性是不能拷贝的</title> </head> <body> <script type="text/javascript"> const obj=Object.create({foo:1},{ //foo 是个继承属性 bar:{ value:2 //bar 是个不可枚举属性 }, baz:{ // baz 是个自身可枚举属性 value:3, enumerable:true, } }); const copy=Object.assign({},obj); console.log(copy);//{baz:3} </script> </body> </html>
在这里咱们知道foo是个继承的属性,而bar是不可枚举属性,baz是个可枚举属性,因此最终只拷贝了baz对象
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>原始类型会被包装为对象</title> </head> <body> <script type="text/javascript"> const v1="abc"; const v2=true; const v3=10; const v4=Symbol('foo'); const obj=Object.assign({},v1,null,v2,undefined,v3,v4); console.log(obj);//{0:a,1:b,2:c} </script> </body> </html>
在这里主要总结两点:1.原始类型会进行包装,null和undefined会被忽略,2.只有字符串的包装对象才可能有自身可枚举属性
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>异常会打断后续拷贝任务</title> </head> <body> <script type="text/javascript"> const target=Object.defineProperty({},"foo",{ value:1, writeable:true }); Object.assign(target,{bar:2},{foo2:3,foo:3,foo3:3},{baz:4}); console.log(target.bar);//2,说明第一个源对象拷贝成功了。 console.log(target.foo2);//3,说明第二个源对象的第一个属性也拷贝成功了。 console.log(target.foo);//1,只读属性不能被覆盖,因此第二个源对象的第二个属性拷贝失败了。 console.log(target.foo3);//undefined,异常以后 assign 方法就退出了,第三个属性是不会被拷贝到的。 console.log(target.baz);// undefined,第三个源对象更是不会被拷贝到的。 </script> </body> </html>
首先咱们先来看第一个对象,在第一个对象中咱们定义了target的属性只读不可写,而后使用Object.assign方法实现拷贝发现bar拷贝成功了,而后继续拷贝,foo2也拷贝成功了,当碰到foo的时候发现目标对象也是foo,原本是会覆盖的可是咱们设置了只读不可写,因此到foo的时候拷贝就失败了,接着就发生了异常,致使后面的拷贝失败了,因此foo3和baz的值为undefined
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>拷贝访问器</title> </head> <body> <script type="text/javascript"> const obj = { foo: 1, get bar() { return 2; } }; let copy = Object.assign({}, obj); console.log(copy); // { foo: 1, bar: 2 } copy.bar的值来自obj.bar的getter函数的返回值 </script> </body> </html>
在这里咱们看到Object.assign()拷贝了对象的访问器,即get bar()函数