淺拷貝,又叫淺復制,使用方法就是最簡單的賦值:
var a = 1; var b = a; var c = {x: 1}; var d = c;
實際上參數傳遞也是用的淺拷貝
但是,在對象進行淺拷貝的時候,拷貝的內容進行修改會影響原來的變量
var a = {x:1}; var b = a; console.log(b); //{x:1} b.x = 2; console.log(b); //{x:2} console.log(a); //{x:2}
原因:對象類型的直接賦值,實際上是賦值的一個引用,或者說只是賦值了一個地址,對象的數據實際上並沒有直接放在這個變量所代表的內存空間,該內存空間只是存放了一個地址,這個地址里面索引到的部分才是真正的數據,當對對象進行直接賦值,實際上是把變量所代表的內存空間里面存放的地址給賦值到了新變量,實際指向的數據依然是同一份數據
深拷貝:
深拷貝的原理其實就是在進行對象復制的時候,人為的去索引引用所指向的真正數據,然后新建一個新的內存地址去存放淺拷貝出來的真正數據,然后讓新變量指向這個人為生成的數據的地址
var a = {x:1}; var b = {}; b.x = a.x; b.x = 2; console.log(a,b); //{x:1} {x:2}
當然,在實際使用中,我們不可能依次去復制
深拷貝的幾種方法:
1.JSON內置的方法
var a = {x:1}; var b = JSON.parse(JSON.stringify(a)); console.log(b); //{x:1} b.x = 2; console.log(b); //{x:2} console.log(a); //{x:1}
ps:該方法原理是將對象轉換成JSON字符串,再轉換回來,json字符串轉換為對象的時候,會自己去構建新的內存地址存放數據
缺點:如果對象屬性為function,因為JSON格式字符串不支持function,在構建的時候會自動刪除
var a = {x:1, y: function() {}}; var b = JSON.parse(JSON.stringify(a)); console.log(b); //{x:1}
2.Object內置方法assign
var a = {x:1}; var b = Object.assign({}, a); console.log(b); //{x:1} b.x = 2; console.log(b); //{x:2} console.log(a); //{x:1}
ps:該方法原理是Object.assign方法實際上是對對象進行拼接, 將后續對象的內容插入到第一個參數指定的對象,不會修改第一個參數之后的對象,而我們將第一個對象指定為一個匿名空對象,實現深拷貝
缺點:對象嵌套層次過深,超過2層,就會出現淺拷貝的狀況,比如echarts組件的option對象
var a = {x: {y: 1}}; var b = Object.assign({}, a); b.x.y = 2; console.log(b); //{x: {y: 2}} console.log(a); //{x: {y: 2}}
3.遞歸方法實現深拷貝
function ObjCopy(obj) { var tmp_obj; if(typeof obj == 'object') { if(obj instanceof Array) { tmp_obj = []; } else { tmp_obj = {}; } } else { return obj; } for (var i in obj) { if (typeof obj[i] != 'object') { tmp_obj[i] = obj[i]; } else if (obj[i] instanceof Array) { tmp_obj[i] = []; for (var j in obj[i]) { if (typeof obj[i][j] != 'object') { tmp_obj[i][j] = obj[i][j]; } else { tmp_obj[i][j] = ObjCopy(obj[i][j]); } } } else { tmp_obj[i] = ObjCopy(obj[i]); } } return tmp_obj; }
var a = {x: {y: {z: 1}}, m: function() {console.log(1);}}; var b = ObjCopy(a); console.log(b); //{x: {y: {z: 1}}, m: function() {console.log(1);}} b.x.y.z = 2; console.log(b); //{x: {y: {z: 2}}, m: function() {console.log(1);}} console.log(a); //{x: {y: {z: 1}}, m: function() {console.log(1);}}
總結:如果在沒有function的情況下,可以直接使用JSON方式,如果在拷貝層次不超過3層的情況下,可以使用Object.assign方式,否則只能通過自己實現深拷貝