JS中的函式引數傳遞到底是按值傳遞還是按引用傳遞
首先我們知道JS中的資料型別大致可以分為簡單資料型別和複雜資料型別;
當我們宣告一個變數並給它賦值時,可以賦給其簡單值和複雜值(以下堆記憶體和棧記憶體的地址表示均隨意取的,只是為了區分,不代表真實的記憶體地址);
針對簡單資料型別:
例1
var simpleData1 = 18
var simpleData2 = simpleData1
simpleData2 = 19
console.log(simpleData1 ) //打印出18
以上例子的過程為:先給simpleData1 在棧記憶體中分配一個地址s101,裡面儲存數字18,然後將simpleData1賦給simpleData2 ,相當於緊接著在棧記憶體中又分配一個地址s102,裡面同樣儲存數字18,這時再將s102中的內容變成19,這當然不會影響s101中的內容。
針對複雜資料型別,以陣列為例
例2
var arr1 = ['zyp','zyp','zyp']
var arr2 = arr1
arr2[0] = 'zyp1'
console.log(arr1) //打印出 ["zyp1", "zyp", "zyp"]
以上例子的過程為:先在堆中開闢一塊地址h1001來存陣列[‘zyp’,‘zyp’,‘zyp’],同時將該堆記憶體的地址h1001存放在棧記憶體s103中,然後再在棧記憶體中開闢一個地址s104同樣存放h1001,這時arr1和arr2指向同一塊堆記憶體,改變其中的值會同時反映在變數arr1和arr2上。
例3
var arr1 = ['zyp','zyp','zyp'] var arr2 = arr1 arr2 = ['zyp1','zyp1','zyp1'] arr2[0] = 'zyp2' console.log(arr2) //打印出 ["zyp2", "zyp1", "zyp1"] console.log(arr1) //打印出 ["zyp", "zyp", "zyp"]
以上例子的過程為:跟上面一樣,先在堆中開闢一塊地址h1001來存陣列[‘zyp’,‘zyp’,‘zyp’],同時將該堆記憶體的地址h1001存放在棧記憶體s103中,然後再在棧記憶體中開闢一個地址s104同樣存放h1001,這時arr1和arr2指向同一塊堆記憶體。不同的是:這時我們又在堆記憶體中開闢出一塊新的地址h1002來存放新陣列[‘zyp1’,‘zyp1’,‘zyp1’],新地址h1002存放在s104中,這時arr2中儲存的地址已經由h1001變成了h1002, 這時再改變h1002對應的堆記憶體中的值,便和arr1沒有任何關係了。
明白了上述賦值過程再來理解函式傳參便是一個道理了
function changeObj(arr1) { arr1= ['a1', 'a1', 'a1'] } var arr = ['a', 'a', 'a'] changeObj(arr) console.log(arr) // 打印出["a", "a", "a"]
這個例子中:假設陣列[‘a’, ‘a’, ‘a’]在堆記憶體中對應的地址為:h2001, 實參arr在棧記憶體中對應的地址為s201, 裡面儲存的是h2001。呼叫changeObj函式時,將arr複製給arr1,這裡對應的操作是自動將在棧記憶體中分配一塊地址s202來儲存h2001,因此arr和arr1對應的是同一塊堆記憶體,但這時又在堆記憶體中開闢新空間h2002來儲存陣列[‘a1’, ‘a1’, ‘a1’],h2002儲存在arr1對應的棧記憶體s202中,這裡的道理就和例3是一樣的了