JavaScript深淺拷貝

深淺拷貝

基本類型和引用類型

  1. ECMAScript 中的變量類型分爲兩類:
  • 基本類型:undefined,null,布爾值(Boolean),字符串(String),數值(Number)
  • 引用類型: 統稱爲Object類型,細分的話,有:Object類型,Array類型,Date類型,Function類型等。
  1. 不一樣類型的存儲方式:

基本數據類型 保存在 棧內存,形式以下:棧內存中分別存儲着變量的標識符以及變量的值。jquery

image

引用類型 保存在 堆內存 中, 棧內存存儲的是變量的標識符以及對象在堆內存中的存儲地址,當須要訪問引用類型(如對象,數組等)的值時,首先從棧中得到該對象的地址指針,而後再從對應的堆內存中取得所需的數據。json

image

對於僅僅是複製了引用(地址),換句話說,複製了以後,原來的變量和新的變量指向同一個東西,彼此之間的操做會互相影響,爲 淺拷貝。數組

而若是是在堆中從新分配內存,擁有不一樣的地址,可是值是同樣的,複製後的對象與原來的對象是徹底隔離,互不影響,爲 深拷貝。函數

深淺拷貝 的主要區別就是:複製的是引用(地址)仍是複製的是實例。性能

js的複製方法

slice和concat方法

var a = [[1,2,3],4,5];
var b = a.slice();
console.log(a === b);
a[0][0] = 6;
console.log(a);
console.log(b);

image

jQuery中的 extend 複製方法

var obj = {name:'xixi',age:20,company : { name : '騰訊', address : '深圳'} };
var obj_extend = $.extend(true,{}, obj); //extend方法,第一個參數爲true,爲深拷貝,爲false,或者沒有爲淺拷貝。
console.log(obj === obj_extend);
obj.company.name = "ali";
obj.name = "hei";
console.log(obj);
console.log(obj_extend);

image

Array 的 slice 和 concat 方法 和 jQuery 中的 extend 複製方法,他們都會複製第一層的值,對於 第一層 的值都是 深拷貝,而到 第二層 的時候 Array 的 slice 和 concat 方法就是 複製引用 ,jQuery 中的 extend 複製方法 則 取決於 你的 第一個參數, 也就是是否進行遞歸複製。prototype

JSON 對象的 parse 和 stringify

JOSN 對象中的 stringify 能夠把一個 js 對象序列化爲一個 JSON 字符串,parse 能夠把 JSON 字符串反序列化爲一個 js 對象,這兩個方法實現的是深拷貝。3d

var obj = {name:'xixi',age:20,company : { name : '騰訊', address : '深圳'} };
var obj_json = JSON.parse(JSON.stringify(obj));
console.log(obj === obj_json);
obj.company.name = "ali";
obj.name = "hei";
console.log(obj);
console.log(obj_json);

image

可是該方法也是有侷限性的:指針

  • 會忽略 undefined
  • 不能序列化函數
  • 不能解決循環引用的對象

這個函數能夠解決大部分問
題,而且該函數是內置函數中處理深拷貝性能最快的。若是你的數據中含有以上三種狀況下,可使用 lodash 的深拷貝函數。code

固然,也能夠利用遞歸本身封裝深度克隆函數,對象

function deepClone(origin, target){
    var target = target || {},
         toStr = Object.prototype.toString,
         arrStr = "[object Array]";

    for(var prop in origin){
        if(origin[prop] !== 'null' && origin.hasOwnProperty(prop)){
            if(typeof(origin[prop]) === 'object') {
                target[prop] = toStr.call(origin[prop]) === arrStr ? [] : {};
                deepClone(origin[prop], target[prop]);
            }else{
                target[prop] = origin[prop];
            }
        }
    }
}
相關文章
相關標籤/搜索