最近再寫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()函數