ES5中的值傳遞/引用傳遞--解釋
先明確一個概念:棧和堆;不要管他們是什麼,你知道有這兩個東西就行;
var num1 = 8;
實際上,宣告的num1這個變數它並沒有直接在棧中儲存一個值:8;
當你var 宣告的時候,在堆中會被分配出一塊記憶體空間,這個空間有兩個資訊,一個是這個空間在堆中的地址,另一個是這個空間實際儲存的一個值:8;
而棧中,給了兩個資訊,有一個識別符號叫做num1,它裡面被放進去了一個堆中的地址,這個地址,就指向堆中那個對應的儲存著值:8的那塊記憶體空間;
var num1 = 8; var num2 = num1;
宣告瞭一個變數num1,值為8,值在記憶體空間裡;
宣告瞭一個變數num2,值為num1的值,將num1的值在記憶體空間中複製一份,然後將複製的那一份記憶體空間的地址放入棧中的num2;
如果這個時候我修改了num2的值,num1是不會改變的,為什麼?
A有兩個兒子,一個叫B另一個叫C,A先給了B一百元錢,這個時候C看見了也想要,但是A就只有100元,於是A就用超能力,將B的一百元複製了一張給了C;
這個時候,B和C都各自有一百元,但是C花了5塊錢買了一個棒棒糖,還剩95元,C花的是自己口袋裡的那一百元,不是B口袋裡的,所以B沒有買棒棒糖,B的口袋裡還是一百元,沒有變;
【值傳遞】
————————————————————————————————————————————————————————————————————
在《JavaScript高階程式設計》中,我讀到這麼一段話:在ECMAScript中,所有函式的引數都是【值傳遞】,不是【引用傳遞】;
先解釋什麼是【值傳遞】:上面的num1和num2就是值傳遞;
舉個例子:
複製程式碼 var a = 10; function foo(num){ return num + 1; }; console.log(foo(a));//11 console.log(a);//10 複製程式碼 函式foo接受一個num引數,在函式體內將傳遞進來的這個引數加1並返回出去;
這個時候,其實num就是一個變數,就是一個相對於foo這個函式的區域性變數,你可以這麼理解:var num = a;
函式的引數是無法在函式外部獲得或使用的;
都說了是值傳遞,所以他是將a的值複製了一份賦給了num,【num的地址指向和a的地址指向在堆中是不同的】,既然都不在同一個記憶體空間內,那我改變其中一個記憶體空間的值,是不可能影響到另一個記憶體空間的值的;
實在是理解不了,看這段程式碼:
複製程式碼 var {log} = console;
let nameArr = ['小紅','小李'];
function add(arr){
log(arguments);
};
add(nameArr);
複製程式碼 啥意思呢?
你肯定還記得arguments,本質上函式的引數列表是一個陣列,不是說值傳遞嗎?你把【值傳遞】倒過來看【傳遞值】;
對,沒錯,傳遞的是值,不是地址;
【引用傳遞】
————————————————————————————————————————————————————————————————————
舉個例子,看程式碼你就明白了:
複製程式碼 var obj0 = { name:'小明' }; var obj1 = obj0; console.log(obj0.name);//小明 console.log(obj1.name);//小明 複製程式碼 物件obj0有個name屬性,值為字串:小明;
我又建立了一個obj1物件,將obj0賦值給obj1;
那麼,在堆中,是有兩個記憶體空間分別儲存著兩個物件嗎?
不是的,其實是這樣的;
這個賦值,其實只是把obj0的地址賦給了obj1,但實際上,在堆中,並沒有一個獨立的物件讓obj1去單獨指著,obj0和obj1的地址共同指向了堆中的同一個物件;
這樣說的話,那麼我不管是在其中任何一個物件上做出修改,都會同時影響另外一個,另一個的相同屬性也會跟著改變;
就是說,當複製儲存物件的某個變數的時候,操作的是物件的引用(地址),當修改新增物件的屬性/方法時,操作的是實際的物件本身;
前方有坑,需謹慎:
複製程式碼 var fun = { name:'小紅' } function setName(obj){ obj.name = '老王' } setName(fun); console.log(fun.name);//老王 複製程式碼
有個fun物件,這個物件有個name屬性,值為"小紅";
執行setName這個函式,將fun這個物件傳遞了進去,這個時候是值傳遞還是引用傳遞?
想都不用想,肯定是值傳遞,因為【JS中所有的函式的引數都是值傳遞】;
那既然是值傳遞,我在函式內部修改了obj這個物件的name是不是不會影響到外面fun物件的name屬性;
按道理來說,肯定是這樣的,但是偏偏就不是,在外面輸出了fun的name屬性,發現被更改了;
實際上是這樣的:var obj = fun;
即使函式的引數是隻能值傳遞,但是obj也會按引用訪問同一個物件;
這裡非常的不好理解
這樣想,純正的將一個物件賦值為另外一個物件,改變其中一個的某個屬性,另一個也會同時發生改變,因為他們是指向了堆中的同一個物件;
上面程式碼中:函式的引數實際上是一個區域性變數,只對函式體內起作用;
而程式碼中將fun的值,傳遞給區域性變數obj,那麼就是這樣:var obj = fun;
實際上,你在setName這個函式中將arguments列印出來你是可以看到,obj的值是一個物件{name:'小紅'};這就更加的進一步證實,JS函式中的引數確實都是值傳遞;
這就對上了,函式的引數都是值傳遞,沒錯,確實是fun的值;
最後:在向引數傳遞引用型別的值的時候,會把這個值在記憶體中的地址也一併複製一份給區域性變數(就是引數);
然後你就能明白這句話:obj還是會按照引用,就是地址,去訪問這個物件,訪問的地址相同,那肯定的,訪問的物件也就是同一個物件了!
然後,然後現在你就已經理解了什麼是基本型別值、引用型別值,什麼是值傳遞,什麼是引用(地址)傳遞;
相關文章
- 關於值傳遞和引用傳遞的解釋
- 值傳遞和引用傳遞
- JavaScript的值傳遞和引用傳遞JavaScript
- Java的值傳遞和引用傳遞Java
- 快速搞懂值傳遞與引用傳遞
- Day30--值傳遞和引用傳遞
- Java - 是值傳遞還是引用傳遞Java
- 面試官問:Go 中的引數傳遞是值傳遞還是引用傳遞?面試Go
- golang工作筆記(二)值傳遞與引用傳遞Golang筆記
- 解惑4:java是值傳遞還是引用傳遞Java
- 這一次,徹底解決Java的值傳遞和引用傳遞Java
- chan中傳遞map資料,傳遞的是引用
- C#|.net core 基礎 - 值傳遞 vs 引用傳遞C#
- Java 從陣列來看值傳遞和引用傳遞Java陣列
- Python的函式引數傳遞:傳值?引用?Python函式
- C#程式設計引用型別和值型別 以及引用傳遞和值傳遞C#程式設計型別
- PHP中物件的引用傳遞PHP物件
- Java是值傳遞還是引用傳遞,又是怎麼體現的Java
- c++指標傳遞與引用傳遞C++指標
- go 值傳遞和地址傳遞的例子Go
- 這一次,讓你徹底理解Java的值傳遞和引用傳遞!Java
- 關於String是值傳遞還是引用傳遞,talk is cheap, just show codes
- Go語言引數傳遞是傳值?還是傳引用 ?Go
- Python引數傳遞,既不是傳值也不是傳引用Python
- 用畫小狗的方法來解釋Java中的值傳遞Java
- JS的方法引數傳遞(按值傳遞)JS
- [精]--這一次,讓你徹底明白Java的值傳遞和引用傳遞!Java
- 引數傳遞方式必須是const引用傳遞
- 面試官:兄弟,說說Java到底是值傳遞還是引用傳遞面試Java
- Golang中函式傳參存在引用傳遞嗎?Golang函式
- java值傳遞Java
- 按值傳遞
- go語言引數傳遞到底是傳值還是傳引用Go
- python的賦值傳遞Python賦值
- Java只有值傳遞Java
- ABAP 方法呼叫的引數傳遞裡,透過引用傳遞的方式,能修改原始引數值嗎?
- 微信小程式中的值傳遞微信小程式
- html、php和js值的傳遞(使用ajax進行傳遞)HTMLPHPJS
- JavaScript 是如何工作的:JavaScript 的共享傳遞和按值傳遞JavaScript