在js中值傳遞和引用傳遞是讓人容易混淆的問題,下面我就來根據自己的理解來區分一下這兩個傳遞方式:
值傳遞
值傳遞是兩個變量傳遞前後互補干擾,無法造成影響,下面代碼舉例說明
var a=7;
function fuc(a){
a++;
}
fuc(a)
console.log(a); //7
向上面這樣,當我們給a賦值之後,在通過調用函數調用吧a的值自增,但是改變的a的值只是在函數中,沒有改變函數外部的值,這種方式傳遞叫做值傳遞,實際的原理可以用堆棧解釋一下:
當我們賦值a=7的時候,因爲數據是基本數據類型,所以存在棧中,而函數fuc的值a是引用數據類型得數據所以存在堆中,而棧中只是存放一個地址,(基本數據類型有哪些,number,string,boolean,null,undefined,symbol以及未來ES10新增的BigInt(任意精度整數)七類。引用數據類型(Object類)有常規名值對的無序對象{a:1},數組[1,2,3],以及函數function(){}等)。如下圖所示:
var a=7時;
fuc(a)時;
所以當我們打印a的值得時候a的值是保存在堆中的因而沒有變。
引用傳遞
值傳遞的時候通過函數調用之後如果沒有在函數中找到所需要的值,會去函數外面找所需要的變量及其值,改變的過程如下:
代碼:
var a=7;
function fuc(){
a++
}
fuc(a);
console.log(a); //8
堆棧中數據存儲:
var a=7;
fuc(a)時,這時候因爲函數中沒有a變量,所以沒有數據保存到堆棧中,所以函數就會去函數外面尋找,就會找到上圖的棧中存貯的a=7,所以在函數調用的時候,改變的是函數外邊的值,也就是存儲在棧中的值。
或者換一種方式理解,代碼如下:
function test(obj){
obj.name = 'lili';
}
var tal = new Object();
test(tal);
console.log(tal); //{name:'lili'}
當函數test創建的時候,會創建一個對象obj:
當我們創建一個空對象tal的時候:
test(tal)的時候:tal=obj,
當調用函數的時候,因爲tal和obj都是引用數據類型,所以都把數據保存在堆中,棧中只是存一個地址,當我們賦值tal=obj的時候,這時就是把tal對象在棧中創建的地址指向改爲和obj是一樣的,都指向obj在堆中的內存數據,這種傳遞數據的方式叫做引用傳遞。
除此之外參數也是按照值傳遞的,具體代碼如下:
function test(obj){
obj.name = 'lili';
var obj = new Object();
obj.name = 'kiki';
}
var tal = new Object();
test(tal);
console.log(tal); //{name:'lili'}
堆棧中的存儲數據過程如下:
然後函數調用:
當重新聲明obj對象的時候,並且賦值之後:
這時候我們看到創建一個新對象,就相當於把obj的值放到一個新的堆中,改變對象obj的值之後,因爲tal對象還是指向之前的obj的堆,所以數據沒有改變,並且由此可以看出,對象的傳遞也是按照引用傳遞的方式來傳遞的。