JavaScript參數傳遞方式

這幾天遇到js參數傳遞方式的問題,深切探究一番,將所得結果總結於此

常見的幾種傳遞方式

傳值調用(call by value)

在傳值調用中實際參數被求值,其值被綁定到函數中對應的變量上(通常是把值複製到新內存區域)。在函數返回後調用者作用域裏的曾傳給函數的任何東西都不會變。

傳引用調用(call by reference)

在“傳引用調用”求值中,傳遞給函數的是它的實際參數的隱式引用(即實際參數的地址)而不是實參的拷貝。通常函數能夠修改這些參數(比如賦值),而且改變對於調用者是可見的。

傳共享對象調用(call by sharing)

在傳共享對象調用中,傳遞給函數的是實參所指向引用對象的地址,而不是實參的地址,即傳遞共享對象。故在函數中修改引用對象時,實參的值也會跟着變化,而如果是重新給新參賦值後,再進行任何修改都不會影響到外面的實參了。

JS中的傳值方式

Number--傳值調用

let a = 1;
function add(val) {
  val += 1;
  console.log(`val=${val}`); // 2
}

add(a);
console.log(`a=${a}`); // 1

String--傳值調用

let a = 'hahaha';
function change(val) {
  val = 'heiheihei';
  console.log(`val=${val}`); // heiheihei
}

change(a);
console.log(`a=${a}`); // hahaha

Boolean--傳值調用

Symbol--傳值調用

let a = Symbol('prop');
function change(val) {
  val = Symbol(2);
  console.log(`val=${val.toString()}`); // Symbol(2)
}

change(a);
console.log(`a=${a.toString()}`); // Symbol(prop)

null--傳值調用

undefined--傳值調用

Object--傳共享對象調用

let obj = {
    a: 1
}
function change(obj) {
    obj.a = 2;
    console.log(obj); // {a: 2}
    obj = {
        a: 3
    }
    console.log(obj); // {a: 3}
}

change(obj);
console.log(obj); // {a: 2}

從上面的代碼可以看出,在函數中對參數所指向的對象進行修改時會影響到外面的實參,但對函數參數重新賦值時,不會影響到實參,故js引用類型的傳值方式爲call by sharing

深入探究

變量存儲方式

圖片描述

C#中類型有兩種:值類型和引用類型,它們之間的卻別在於實際數據存儲的位置(如上圖)。值類型的變量和實際數據都存儲在堆棧中;而引用類型則只有變量存儲在堆棧中,變量存儲着實際數據的地址,實際數據存儲在與地址相對應的託管堆中。

C#中的值傳遞

  • 正常情況下,值類型按值傳遞
  • 正常情況下,應用類型按共享對象的方式傳遞(call by sharing),但string類型除外(由於string的不可變性,它是按值傳遞的)
  • 通過使用ref或out關鍵字,值類型和引用類型都可以按引用傳遞

總結

綜上所述(證明題2333),值傳遞和引用傳遞的參數類型既可以是值類型又可以是引用類型,但是call by sharing的參數類型只能是引用類型。

個人理解:JS中,null賦值的變量時對象,但是,變量指向的引用地址爲空,故在函數中修改參數的值,對實參不會又任何影響,所以是按值傳遞。string類型應該跟C#按值傳遞的原因一致。

參考:
維基百科
JS中的值是按值傳遞,還是按引用傳遞呢
《Learning hard C#學習筆記》第10章

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章