JS基本類型-引用類型-深淺拷貝


在JavaScript中變量包含兩種類型的值:一種是基本類型,一種是引用類型。

基本類型包括:數值、字符串、null、undefined、布爾值
引用類型包括:對象、數組、函數、正則…

 

補充: null和undefined的區別

null表示"沒有對象",即該處不應該有值。

  典型用法是:

(1) 作為函數的參數,表示該函數的參數不是對象。

(2) 作為對象原型鏈的終點。

undefined表示"缺少值",就是此處應該有一個值,但是還沒有定義。

  典型用法是:

(1)變量被聲明了,但沒有賦值時,就等於undefined。

(2) 調用函數時,應該提供的參數沒有提供,該參數等於undefined。

(3)對象沒有賦值的屬性,該屬性的值為undefined。

(4)函數沒有返回值時,默認返回undefined。

1.引用類型的動態屬性

對於引用類型的值,我們可以為其添加屬性和方法,也可以改變或刪除屬性和方法,

對於基本類型的值,盡管給其添加屬性和方法不會報錯,但這是無效的。

var obj=new Object();
obj.name="zuobaiquan";
var str="zbq";
str.age=20;
console.log(obj.name);// zuobaiquan
console.log(str.age);// undefined

2.基本類型值和引用類型值的復制

2.1基本類型值

基本類型值是指在棧內存保存的簡單數據段,在復制基本類型值的時候,會開辟出一個新的內存空間,將值復制到新的內存空間。

var a = 1;
var b = a;
a = 2;
console.log(a);//輸出2;
console.log(b);//輸出1;

var a = 1;

var b = a;

a = 2;

從上面例子看出,當一個變量的值是基本類型,把它復制給另一個變量,復制完成后改變它的值,不會影響已經復制了它的值的變量。

2.1引用類型值

引用類型值是保存在堆內存中的對象,變量保存的只是指向該內存的地址,在復制引用類型值的時候,其實只復制了指向該內存的地址。

var a = {
   name: 'Kitty',
   age: '20',
   sex: 'man'
};
var b = a;
a.name = 'Jack';
console.log(a);//輸出{name: 'Jack',age: 20,sex: 'man'}
console.log(b);//輸出{name: 'Jack',age: 20,sex: 'man'}

var a = {name: ‘Kitty’,age: ‘20’,sex: ‘man’};

var b = a;

a.name = ‘Jack’;

從上面例子看出,當一個變量的值是引用類型值,把它復制給另外一個變量,復制的只是指向儲存對象內存的地址,所以復制完成后,改變它的值,會影響復制了它的值的變量。
注意:如果有兩個變量的值是引用類型值,就算它們的值完全相同,它們也是不相等的,因為它們指向的內存地址不同,例子:

3.對象的淺拷貝和深拷貝

當一個變量是對象,如果像上面那樣直接將一個變量賦值給另一個變量,如果改變某個變量的值,另外一個變量也會跟着改變,如果我們不想發生這種情況,就需要寫一個函數用來拷貝對象。

3.1淺拷貝

當對象里的屬性的值只有基本類型的值時候。

var a = {
     name: 'Kitty',
     age: 12,
     sex: 'man'
}
function copy(obj){
    var newObj = {};
    for(vl in obj){
         newObj[vl] = obj[vl] 
    }
    return newObj;
}

例子:

從上面例子看到,我們通過這種方式拷貝對象,改變某個變量的值,並不會影響另一個變量。

3.1深拷貝

當對象里的屬性的值還是一個對象,這時候用上面的方法就不行了,例子:

這時候要改進這個函數:

使用遞歸的方法:

 

function deepCopy(obj){
     var newObj = {};
     for(vl in obj){
         if(typeof obj[vl] === 'object' && obj[vl] !== null){
             newObj[vl] = deepCopy(obj[vl]);
         }else{
             newObj[vl] = obj[vl];
         }       
     }
     return newObj;
}

例子:

使用JSON的方法:

JSON.stringify(),將一個對象解析成字符串。
JSON.parse(),從一個字符串中解析出json 對象。

我們可以使用上面兩個個方法來進行對象的深拷貝:

JSON.parse(JSON.stringify());

例子:

 

JSON.parse(JSON.stringify(obj)) 實現深拷貝的一些坑

1.如果json里面有時間對象,則序列化結果:時間對象=>字符串的形式;

let obj = {
    age: 18,
    date: new Date()
};
let objCopy = JSON.parse(JSON.stringify(obj));
console.log('obj', obj); // {age: 18, date: Thu Mar 12 2020 15:39:35 GMT+0800 (中國標准時間)}
console.log('objCopy', objCopy); //{age: 18, date: "2020-03-12T07:39:35.372Z"}

 

2.如果json里有RegExp、Error對象,則序列化的結果將只得到空對象 RegExp、Error => {};

let obj = {
    age: 18,
    reg: new RegExp('\\w+'),
    err: new Error('error message')
};
let objCopy = JSON.parse(JSON.stringify(obj));
console.log('obj', obj); //{age: 18, reg: /\w+/, err: Error: error message
    at <anonymous>:4:10}
console.log('objCopy', objCopy); // {age: 18, reg: {…}, err: {…}}

 

3.如果json里有 function,undefined,則序列化的結果會把 function,undefined 丟失

let obj = {
    age: 18,
    fn: function () {
        console.log('fn');
    },
    hh: undefined
};
let objCopy = JSON.parse(JSON.stringify(obj));
console.log('obj', obj); //{age: 18, hh: undefined, fn: ƒ}
console.log('objCopy', objCopy); //{age: 18}

 

4.如果json里有NaN、Infinity和-Infinity,則序列化的結果會變成null;

let obj = {
    age: 18,
    hh: NaN,
    isInfinite: 1.7976931348623157E+10308,
    minusInfinity: -1.7976931348623157E+10308
};
let objCopy = JSON.parse(JSON.stringify(obj));
console.log('obj', obj); //{age: 18, hh: NaN, isInfinite: Infinity, minusInfinity: -Infinity}
console.log('objCopy', objCopy); //{age: 18, hh: null, isInfinite: null, minusInfinity: null}

 

5.如果json里有對象是由構造函數生成的,則序列化的結果會丟棄對象的 constructor;

6.如果對象中存在循環引用的情況也無法實現深拷貝

來源:https://segmentfault.com/a/1190000020297508

 

如何拷貝數組呢

拷貝一個數組但是對副本的修改不影響原來的數組

//方法1
var a = [1,2,3];
var b = a.slice(0);
a.reverse();
console.log(a);//[3,2,1]
console.log(b);//[1,2,3]

//方法2 var c = [4,5,6]; var d = c.concat(); c.reverse(); console.log(c);//[6,5,4] console.log(d);//[4,5,6] //方法3 var arr = [1,2,3,4,5] var [ ...arr2 ] = arr arr[2] = 5 console.log(arr) console.log(arr2) //方法4 var arr = [1,2,3,4,5] var arr2 = copyArr(arr) function copyArr(arr) { let res = [] for (let i = 0; i < arr.length; i++) { res.push(arr[i]) } return res }

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM