在《JavaScript高級程式設計》第三版 4.1.3,講到傳遞參數: ECMAscript中所有函數的參數都是按值傳遞 按值傳遞 也就是,把函數外部的值複製給函數內部的參數,就和把值從一個變數複製到另一個變數一樣 當傳遞value給函數foo的時候,相當於拷貝一份value給foo假設拷貝的那份 ...
在《JavaScript高級程式設計》第三版 4.1.3,講到傳遞參數:
ECMAscript中所有函數的參數都是按值傳遞
按值傳遞
也就是,把函數外部的值複製給函數內部的參數,就和把值從一個變數複製到另一個變數一樣
var value = 1;
function foo(v) {
v = 2;
console.log(v); //2
}
foo(value);
console.log(value) // 1
當傳遞value給函數foo的時候,相當於拷貝一份value給foo假設拷貝的那份叫v,函數中修改的都是v,不會一項原來的value值
引用傳遞
按值傳遞裡面的拷貝雖然好理解 但是當值是一個複雜的數據結構的時候,拷貝就會產生性能問題
所以還有另外的傳遞方式叫做按引用傳遞
所謂按引用傳遞,就是傳遞對象的引用,函數內部對參數的任何改變都會影響該對象的值,因為兩者引用的是同一個對象
var obj = {
value : 1
};
let foo = (o)=> {
o.value = 2;
console.log(o.value);
}
foo(obj)
console.log(obj.value);
這裡產生了一個疑問?
紅寶書都說了 ECMAScript 中所有函數的參數都是按值傳遞的,這怎麼能按"引用傳遞"成功呢?
我們看第三個例子
var obj = {
value: 1
};
function foo(o) {
o = 2;
console.log(o); //2
}
foo(obj);
console.log(obj.value) // 1
如果 JavaScript 採用的是引用傳遞,外層的值也會被修改吶,這怎麼又沒被改呢?所以真的不是引用傳遞嗎?
這就要講到其實還有第三種傳遞方式,叫按共用傳遞。
而共用傳遞是指,在傳遞對象的時候,傳遞對象的引用的副本。
關鍵點:
運算符
=
就是創建或修改變數在記憶體中的指向.
初始化變數時為創建,重新賦值即為修改.
為瞭解釋上面的共用傳遞 這裡在看一個例子摸清楚記憶體中的分佈
var a = {b: 1};// a = {b: 1}
var c = a;// c = {b: 1}
a = 2;// 重新賦值a
console.log(c);// {b: 1}
- 創建變數a指向對象{b:1}
- 創建變數c指向對象{b:1}
- a又重新指向常量2
但是這時候c依舊指向對象{b:1}
這樣我們回頭看第一個例子
var value = 1;
function foo() {
var v = value; // 創建變數v指向value所指向的值
v = 2;// v重新指向另外的值
console.log(v); //2
}
foo(value);
console.log(value) // 1,value從始至終都未改變指向.
現在吧第一個例子修改成對象
var a = {b: 1};// a = {b: 1}
var c = a;// c = {b: 1}
a.b = 2;// 重新賦值對象a中的屬性b
console.log(c);// {b: 2}
棧 | 堆 | 常量區 |
---|---|---|
a,c | [object] | |
b | 1 |
執行完a.b = 2
後:
棧 | 堆 | 常量區 |
---|---|---|
a,c | []object | |
b | 2 |
a,c從始至終都沒有改變指向,變的是b而已
現在再看第二個例子
var obj = {
value: 1
};
function foo() {
var o = obj;
o.value = 2;// 變數value改變了指向,而o並未改變
console.log(o.value); //2
}
foo(obj);
console.log(obj.value) // 2
所以 js始終是按值傳遞,在這裡稱他為共用傳遞