js資料型別賦值,淺拷貝,深拷貝

田小菜發表於2019-05-01

直接上程式碼是我的風格

一,賦值

  1. 基本資料型別的賦值
    var a = 10;
    var b = a;
    b = 24;
    console.log(a); // 10  a不受b的影響。
    console.log(b) // 24
    // 基本資料型別賦值時。。是copy一份10的值。
    // 當b=24時。a不受b的影響。
複製程式碼
  1. 複雜資料型別的賦值
    var obj = {
        age: 12
    }
    var obj1 = obj;
    obj1.age = 18;
    console.log(obj); // {age: 18}
    console.log(obj1); // {age: 18}
    // 複雜資料型別賦值時。。是copy一份引用地址如0x1111。
    // 當obj1 = obj;時。obj和obj1引用一樣。指向同一片堆記憶體空間。
    // 所以當obj1.age = 18時。同樣也會更改obj2。
複製程式碼

二,淺拷貝與深拷貝

注意: 淺拷貝和深拷貝都主要針對複雜資料型別

  1. 淺拷貝:淺拷貝只複製指向某個物件的指標,而不復制物件本身,新舊物件還是共享同一塊記憶體。
  2. 深拷貝:但深拷貝會另外創造一個一模一樣的物件,新物件跟原物件不共享記憶體,修改新物件不會改到原物件。

二,淺拷貝與賦值

  1. 淺拷貝
    // 直接上程式碼吧
    function shallowCopy(oldObj) {
        var newObj = {};
        for(var prop in oldObj) {
            // 所有繼承了 Object 的物件都會繼承到 hasOwnProperty 方法。
            // 這個方法可以用來檢測一個物件是否含有特定的自身屬性;如果有返回true。否則返回false
            // 和 in 運算子不同,該方法會忽略掉那些從原型鏈上繼承到的屬性。
            if(oldObj.hasOwnProperty(prop)){
                newObj[prop] = oldObj[prop]
            }
        }
        return newObj;
    }
    // 淺拷貝
    var obj1 = {
        a: 1, 
        b: [2,3,4], 
        c: [[5,6]] // 注意:這裡多一層引用資料型別
    }
    var obj2 = shallowCopy(obj1); 
    
    obj2.a = 18;
    obj2.b = ['二', '三', '四'];
    obj2.c[0] = ['五', '六'];
    
    console.log('obj1===',obj1) 
    console.log('obj2===',obj2) 
    
    // 如果物件只有一層。。深拷貝 和 淺拷貝一樣。
    
    
複製程式碼

js資料型別賦值,淺拷貝,深拷貝

  1. 賦值
     // 賦值
    var obj1 = {
        a: 1, 
        b: [2,3,4], 
        c: [[5,6]] // 注意:這裡多一層引用資料型別
    }
    var obj3 = obj1;
    
    obj3.a = 18;
    obj3.b = ['二', '三', '四'];
    obj3.c[0] = ['五', '六'];
    
    console.log('obj1===',obj1) 
    console.log('obj3===',obj3) 
    
    // 共享一片記憶體。所有值都會改變。
    
複製程式碼

js資料型別賦值,淺拷貝,深拷貝

三,淺拷貝實現方式

  1. 自己封裝
     function shallowCopy(oldObj) {
        var newObj = {};
        for(var prop in oldObj) {
            // 所有繼承了 Object 的物件都會繼承到 hasOwnProperty 方法。
            // 這個方法可以用來檢測一個物件是否含有特定的自身屬性;如果有返回true。否則返回false
            // 和 in 運算子不同,該方法會忽略掉那些從原型鏈上繼承到的屬性。
            if(oldObj.hasOwnProperty(prop)){
                newObj[prop] = oldObj[prop]
            }
        }
        return newObj;
    }
複製程式碼
  1. 使用Object.assign()
    var pj = { a: {a: "彭彭", b: 39} };
    var pj1 = Object.assign({}, obj);
    pj1.a.a = "wade";
    console.log(pj.a.a); //wade
    
複製程式碼

注意:當object只有一層的時候,是深拷貝

    var pj = { a: {a: "彭彭", b: 39} };
    var pj1 = Object.assign({}, obj);
    pj1.a.a = "wade";
    console.log(pj.a.a); //wade
    
複製程式碼
  1. 陣列的淺拷貝
    // 第一種
    let arr = [1, 3, {
        username: '彭彭'
    }];
    let arr2=arr.concat();    
    arr2[2].username = '君';
    
    console.log(arr[2].username); // 君
    
    // 第二種
    let arr = [1, 3, {
        username: ' 彭彭'
    }];
    let arr3 = arr.slice();
    arr3[2].username = '君';
    console.log(arr[2].username); // 君
    
    // 一般很少用到陣列的拷貝。
    // 陣列淺拷貝和物件是一樣的
複製程式碼

原陣列的元素會按照下述規則拷貝:

  • 如果該元素是個物件引用(不是實際的物件),slice 會拷貝這個物件引用到新的陣列裡。兩個物件引用都引用了同一個物件。如果被引用的物件發生改變,則新的和原來的陣列中的這個元素也會發生改變。
  • 對於字串、數字及布林值來說(不是 String、Number 或者 Boolean 物件),slice 會拷貝這些值到新的陣列裡。在別的陣列裡修改這些字串或數字或是布林值,將不會影響另一個陣列。

四,深拷貝

  1. JSON.parse(JSON.stringify())
    var pj = {
        name: '彭彭',
        handle: function(){} 
    };
    
    var deepPj = JSON.parse(JSON.stringify(pj)); // {name: "彭彭"}。。這種方式弊端在於無法拷貝方法。
複製程式碼
  1. 自覺手動封裝了
    function deepCopy(oldObj) {
        var newObj;
        var oldObjType = Object.prototype.toString.call(oldObj).slice(8, -1);
        if(oldObjType === 'Object'){
            newObj = {};
        }else if(oldObjType === 'array'){
            newObj = [];
        }else{
            return oldObj;
        }
        
        for(let prop in oldObj){
            let value = oldObj[prop];
            let valueType = Object.prototype.toString.call(value).slice(8, -1);
            if (valueType === 'Object' || valueType = 'Array') {
                deepCopy(value);
            } else {
                newObj[prop] = value;
            }
        }
        
        return newObj;
    }
複製程式碼
  1. 借用第三方庫 函式庫lodash
  • 該函式庫也有提供_.cloneDeep用來做 Deep Copy
var _ = require('lodash');
var obj1 = {
    a: 1,
    b: { f: { g: 1 } },
    c: [1, 2, 3]
};
var obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f); // false
複製程式碼

參考文章:juejin.im/post/5b5dcf…

相關文章