我們知道,JS是可分為基本數(shù)據(jù)類型和引用類型兩大類的,基本類型包括Undefined、Null、Boolean、Number和String,而引用類型在JS中即為Object,這里我直接用對象一詞。
我們也知道,對對象的更改會反映到另一個變量:
var obj1 = {
name: 'ceido'
}
var obj2 = obj1;
obj1.name = "haha";
console.log(obj2.name); // "haha"
但是,很長時間里,我都對引用這個詞有誤解,我以為引用就是對象本身!
因為對對象的更改會反映到另一個變量呀。所以我理所當然的以為以下代碼會輸出為 null:
var obj1 = {
name: 'ceido'
}
var obj2 = obj1;
obj1 = null;
console.log(obj2); // { name: 'ceido' }
這時候我才明白,引用只是一個名字,它只是指向?qū)ο蟮囊粋€變量!引用不是對象本身!
就像魯迅又名周樹人,我們說到周樹人的時候,都知道說的是魯迅。也就是說魯迅和周樹人都是指向他這同一個人。但假如哪一天魯迅說:“別叫我周樹人了,就叫我魯迅”。就相當于:周樹人 = null;周樹人這個名字沒了,但魯迅還是魯迅,這個人并不會有什么改變。
一個對象可以有多個引用,就像一個人可以有多個名字一樣,引用也叫別名。
這樣,對于函數(shù)的按值傳遞就很好理解了:
function setName(obj) {
obj.name = "qi";
}
var person = {
name: "ceido"
}
setName(person);
console.log(person); // "qi"
我之前一直很不理解,不是說按值傳遞嗎?這樣傳遞的對象會深復制吧,實參和形參應(yīng)該互不影響啊,那對副本的改變怎么會反映到原對象呢。現(xiàn)在我明白了:的確是深復制,但復制的不是對象!而只是這個引用??!只是指向這個對象的變量啊!
所以形參(obj)即也是對象的一個別名而已,即相當于var obj = person;
function sayName(obj) {
obj.name = "qi";
obj = new Object();
obj.name = "qi";
}
var person = {
name: "ceido"
}
setName(person);
console.log(person); // "qi"
上面的代碼也好理解了,obj = new Object();對引用的賦值,即只是改變了引用的指向。對對象本身沒有影響。
雖然很簡單的概念,但我覺得理解好了很重要。
另外誤以為引用就是對象的原因我覺得還有:
①我們會習慣直接說某某對象,比如上面的person對象,而不會說person這個引用指向的對象。
②我們會說把某個變量賦值為null來釋放內(nèi)存,如 obj = null;
其實這樣說法也不對的。這個做法叫做解除引用,其實真的只是僅僅解除引用而已。
解除一個值的引用并不意味著自動回收該值所占用的內(nèi)存。解除的真正作用是讓值脫離執(zhí)行環(huán)境,以便垃圾收集器下次運行將其回收?!獊碜浴秊s高程》
③當對象只有一個引用時,將引用賦值為null:obj = null;
你可能還會說,這個對象的確被釋放了啊,你看我都用不了了。額,對象引用次數(shù)都為0了,那則說明沒有辦法再訪問這個對象了,當然用不了了。但對象還是存在內(nèi)存中的, 等垃圾收集器下次運行時會將其回收。
所以,可以總結(jié)為:
當復制保存某個對象的某個變量,操作的是對象的引用。
如:
obj = null; obj = new Object(); 等等
但為對象添加、刪除、修改屬性時,操作的是實際的對象。如:
obj.name = 'qi';
obj.age = 100;
delete obj.age; ...
在js高程中也將引用稱為指針,在C++中引用和指針是不同的。
在JS中,我理解為:引用、指針、別名。都是一個意思。都是指向?qū)ο蟮囊粋€變量而已。