天天看點

JavaScript基本類型和引用類型的差別和注意點

前天剛學完Javascript基礎文法,現在對知識點進行梳理,當梳理到數組的常用方法中的splice()方法時,裡面提到了淺拷貝的概念。查閱了相關部落格:Java 淺拷貝和深拷貝的了解和實作方式,發現要了解淺拷貝和深拷貝的差別,重點還是要了解基本資料類型和引用資料類型的複制過程差別。

splice()方法介紹:該方法傳回一個新的數組對象,這一對象是一個由 begin和 end(不包括end)決定的原數組的淺拷貝。原始數組不會被改變。MDN官網資料:Array.slice()

Javascript基本資料類型和引用資料類型的差別和注意點

差別

差別1:基本資料類型的資料值存儲在棧記憶體中,引用資料類型的資料值存儲在堆記憶體中

基本資料類型的資料值存儲在棧記憶體中,變量指向這塊棧記憶體的資料值。通過變量找到這個資料值,隻需要一步。

而引用資料類型不僅有資料值,還有一個專門指向這個資料值的位址值(了解為這個資料值的位址管家),并且資料值存儲在堆記憶體中,位址值存儲在棧記憶體中。變量指向位址值,而位址值指向堆記憶體中的資料值。而通過變量找到這個存儲在堆記憶體中的資料值,需要兩步。

JavaScript基本類型和引用類型的差別和注意點

差別2:變量複制時,基本資料類型複制的是資料值,引用資料類型複制的是位址值

基本資料類型的變量複制時,複制的是變量的資料值。

而引用資料類型的變量複制時,複制的是變量的指向堆記憶體中資料值的位址值。兩個相同的位址值,指向同一塊堆記憶體中的資料值。

代碼用JavaScript編寫

基本資料類型變量複制代碼:

var num1 = 10;
//将num1的值複制給num2
var num2 = num1;
//複制後,改變num1的值
num1 = 20;
//列印num1和num2,看改變num1的值,是否會影響到num2
console.log(num1, num2);
           

代碼運作結果:

JavaScript基本類型和引用類型的差別和注意點

引用資料類型變量複制代碼:

var person1 = {
            name: "張三",
            age: 18,
            sayHi: function f() {
                console.log(this.name + 'say: "My name is' + this.name + '"');
            }
        };
//将person1複制給person2        
var person2 = person1;
//複制後,改變person1的資料值
person1.name = '李四';
person1.age = 20;
//看改變person1的資料值,對person2的資料值影響
console.log(person2.name,person2.age);
person1.sayHi();
           

代碼運作結果:

JavaScript基本類型和引用類型的差別和注意點

基本類型的變量複制過程:首先在棧記憶體中,開辟一塊新的記憶體空間,然後将變量num1的資料值(10)複制到這塊新的棧記憶體空間中,變量num2指向新的棧記憶體空間資料值。兩個變量指向的資料值互不幹擾。

JavaScript基本類型和引用類型的差別和注意點

引用類型的變量複制過程:首先在棧記憶體中,開辟一條新的記憶體空間,然後将變量person1的位址值!位址值!位址值!(牢記)複制到新的棧記憶體空間中,使變量person2指向新的棧記憶體空間中的位址值。兩個位址值相同,指向同一塊堆記憶體中的資料值。

JavaScript基本類型和引用類型的差別和注意點

注意點

注意點1:

切記:引用資料類型隻有new時,才會在堆記憶體中開辟新的記憶體空間

引申:new的過程,你真的了解了new的過程了嗎?

注意點2:

java中的String是引用資料類型,而JavaScript中的String類型是基本資料類型,在字元串調用字元串的方法時,系統自動建立一個臨時字元串對象,當字元串調用完方法後,臨時對象被銷毀。

String類型比較特殊,其值不變性也要引起注意。

值不變性:改變String類型資料值時,不像其他基本資料類型,在記憶體中直接修改資料值。而Sting類型修改資料值時,需3步:

1.首先需要重新開辟一塊記憶體空間,并将原來的資料值複制一份到新的記憶體空間

2.然後在新的記憶體空間中,對資料值進行修改。

3.将變量指向新的記憶體空間的資料值。

原來的記憶體空間沒有了引用,系統會過一段時間将其回收。但具體過多久,就不知道了。是以應該避免大量對String類型資料值的修改。

注意點3:

由此引申的知識點:淺拷貝和深拷貝的差別,但隻要記住并了解三點,萬變不離其宗。1.引用資料類型變量的複制,隻是将指向堆記憶體中的資料值的位址值複制了一份,兩個位址值指向同一塊堆記憶體。2.引用資料類型隻有new時,才會在堆記憶體中開辟新的記憶體空間。3.對String類型資料值的修改,系統會開辟一塊記憶體空間,并将資料值複制給新的記憶體空間,在新的記憶體空間中,對複制的資料值進行修改,變量重新指向新記憶體空間中資料值。具體可參考:Java 淺拷貝和深拷貝的了解和實作方式