目錄
引言
JavaScript的函數參數到底傳的是個啥?
有三種看法:
傳值
傳引用
基礎類型傳值 對象類型傳引用
傳值?
首先我們來看看是不是傳值
// 例子1
function change_list(orig_list) {
new_list = orig_list;
new_list.push('new');
return new_list;
}
orig_list = ['old'];
new_list = change_list(orig_list);
console.log('orig list: ' + orig_list);
console.log('new list: ' + new_list);
打印如下:
orig list: old,new
new list: old,new
由于orig_list都和new_list都發生了變化 因此
JavaScript不是傳值 更像是傳引用
傳引用?
那到底是不是傳引用呢? 我們來看看下面的這個例子
// 例子2
function inc(n) {
n = n + 1;
console.log('[in] n = ' + n);
}
n = 1;
inc(n);
console.log('[out] n = ' + n);
打印如下:
[in] n = 2
[out] n = 1
由于inc函數里和函數外的n并不一致 因此
JavaScript不全是傳引用 有時也傳值
基礎類型傳值 對象類型傳引用?
看到這里機智的你 已經發現了"正確"的答案: 基礎類型傳值 對象類型傳引用
關于JavaScript類型的更多介紹請參考JavaScript學習 之 類型
按照上面的兩個例子 這個答案看起來確實是對的 那么是不是真的是這樣呢? 來看下面的例子
// 例子3
function change_me(orig_list) {
new_list = orig_list;
if (new_list.length < 3) {
new_list = [1000];
} else {
new_list = new_list.push(1000);
}
}
var orig_list = [1];
change_me(orig_list);
console.log(orig_list);
orig_list = [1, 2, 3];
change_me(orig_list);
console.log(orig_list);
按照上述答案 此時orig_list是對象類型所以傳引用 那么在調用change_me之后 期望的打印結果如下
// 期望的打印結果
[ 1000 ]
[ 1, 2, 3, 100]
那么實際的打印結果是否如期望的那樣呢 使用babel-node執行該文件后 實際的打印結果如下
// 實際的打印結果
[ 1 ]
[ 1, 2, 3, 100]
關于babel-node的更多介紹請參考JavaScript學習 之 版本
同時是對象類型 為什么會這樣呢?
第一次像是傳值
第二次像是傳引用
看來這種解釋也是不對的 那JavaScript的參數到底是傳得啥呢? 我已經暈了
傳共享!
正確的表述應該是:
傳共享(call-by-sharing)
當然 也可以說是傳對象(call-by-object)或傳對象的共享(call-by-object-sharing)
關于call-by-sharing的更多解釋請參考這里
但是 什么叫做傳共享 這個概念完全沒聽過啊!
首先 來看看例子1
傳入的orig_list 在push操作之后 函數外的orig_list也被修改了
接著 再看看例子2
傳入的n 在"n = n + 1"操作之后 函數里n的值為2 而函數外n的值仍然為1
最后 來看看例子3
傳入的orig_list 在賦值新的對象時 函數外的orig_list并沒有修改 而push操作時 函數外的origi_list會被修改
因此 我們可以這樣理解傳共享
對對象進行修改時 調用者和被調用者之間共享這個對象 表現出來就像傳引用
對不可變的基本類型進行修改或者給對象賦值新的對象時 調用者和被調用者引用的已經不是同一個對象 表現出來就像傳值
如果你覺得拗口, 那我只能說: 回頭再看一遍例子吧!
小結
JavScript這種區分不可變 / 重新賦值和可變對象的做法 其實也是很多編程語言采取的一種通用做法
例如Python也有類似JavaScript的參數傳遞方式 詳見Python函數參數是傳值還是傳引用?
這樣設計的目的 我認為是為了提高效率 包括: 對象分配和內存使用的效率
當只是對可變對象進行修改 那么就不必分配新的對象 共享同一個共享 表現出來就像傳引用
當需要修改不可變對象或者賦值新的對象 那么不得不分配新的對象 不再共享同一個對象
用一句話描述就是:
引用優先 按需分配
不知道機智的你 是如何理解JavaScript的參數傳遞的呢? 希望讀者也分享你的觀點和依據 我們一起討論和完善對JavaScript參數傳遞的認識
參考
更多文章, 請支持我的個人博客