您現在的位置是:首頁 > 手機遊戲首頁手機遊戲

JS之函式傳參與深淺複製原理

簡介總結由於js中資料型別不同,變數儲存的值也有兩種儲存方式,在堆裡面和在棧面,儲存方式不同,也就導致了讀取方式不同,也就導致了複製操作的結果不同,而引數傳遞和深淺複製都是資料複製的操作

陣列如何傳引數

很多問題看似複雜,沒有章法,事實上卻有著千絲萬縷的聯絡,陳道長此次闡述因為資料型別不同而引發的問題,本文主要探討JS函式引數傳遞規則、淺複製、深複製的原理。

JS之函式傳參與深淺複製原理

變數型別和儲存

首先要明確js中變數的特點,

JS變數本身沒有型別,只有值有型別

。這句話怎麼理解呢,先看下面這段程式碼。

javascript

let a = 42

typeof a //‘number‘

注意返回的是’number‘,不是number,typeof檢測的不是a的型別,而是42的型別,也就是a是沒有型別的,只有a的值有型別。

JS總共有7種資料型別:Number、String、Boolean、Null、Symbol、Undefined、Object。Object是引用型別,其他的是基本型別。至於陣列和函式屬於Object的子型別。不過typeof 一個函式的時候 會返回’function‘,這是為了彰顯函式是一等公民的地位。它要特殊一點。

我們在宣告一個變數時,會給變數進行賦值,變數在儲存的時候也有區別。

基本型別值存放在棧中,可以直接訪問。引用型別值存放在堆記憶體中

。很關鍵的一點:JS是不允許直接訪問記憶體的,所以當一個變數的值是Object時,它儲存的只是一個指標,指向的是Object存放的記憶體地址。

定義一個var a = {{型別值}};b = a,會出現下面兩種情況:1、當型別值是基本型別時,a和b值雖然相同,但確是兩個獨立的變數。2、當型別值是Object時,a和b儲存的是一樣的指標,指向了共同的地址。所以再修改a或者b時,1會有各自的變化,2會兩個變化完還是一樣。

S函式引數

事實上,引數傳遞就是受到資料型別的影響。JS的函式有幾個特性:1、引數沒有個數限制,不管你函數里要用幾個,它卻可以接收任意多個,因為不用它操心,來的這麼些引數都放到了一個引數數組裡。另外引數值也沒有型別限制,非常的開放,然後函式內再透過arguments物件去訪問這個陣列,拿到引數,所以引數不跟函式直接打交道,就好比中間有個傳話的。

所以這也是為什麼es6之前中不能直接給函式引數指定預設值

es6新搞了個rest引數,它搭配了一個數組,變數多餘的引數會存放到這個數組裡,就不用arguments物件來獲取了。

javascript

// arguments變數的寫法

function sortNumbers() {

return Array。prototype。slice。call(arguments)。sort();

}

// rest引數的寫法

const sortNumbers = (。。。numbers) => numbers。sort();

引數傳遞問題

重點來了!

函式引數傳遞其實就是把函式外的值複製給函式內部的值,也就是按照上面的規則來。

引數來自外部,要傳遞到函數里,找個中間變數,

JS是引數是按“值”傳遞的,這個“值”就是變數的值。當變數的值屬於基本型別,這個“值”就是普通值,當變數的值是引用型別時,這個“值”時引用型別的地址

傳遞的引數值是基本型別值會複製給一個區域性變數。傳遞的引數是引用型別的值,複製的是地址。

深淺複製

為啥存在淺複製和深複製,原因和上面一樣。當我們想把物件a賦值給變數b,你會發現b和a指向的是一個地方。b改變的時候a也會變。這就是因為變數儲存的只是個指標,引用型別的值是放在記憶體中,沒法直接訪問。

普通複製就是淺複製,新物件修改時,老物件也會發生變化。

但是我們想把b複製給a後,然後兩個物件互不干擾,完成這樣的複製,這就是深複製。

深複製的原理就是把a物件的每個屬性的值遍歷一遍,然後把它複製給一箇中間值,它作為普通的值進行復制到b物件的屬性。這就回到了基本變數的複製問題。

當然一個物件的屬性也可能是物件,例如:obj = [{a:1},{b:2}],我們想把obj賦值給新物件,這個時候就得遞迴遍歷了,把物件中a屬性的值1和b屬性的值2都給取到,然後把1和2再複製到新的物件裡去,這個時候新物件就不會影響到之前的物件了。

說的有點繞,就是要切斷新物件和老物件的關係,但是咱們又沒辦法直接操作記憶體,就只能透過引用取到老物件中存的資料值,拿出來之後放到新物件裡。這就是深複製的思想。

總結

由於js中資料型別不同,變數儲存的值也有兩種儲存方式,在堆裡面和在棧面,儲存方式不同,也就導致了讀取方式不同,也就導致了複製操作的結果不同,而引數傳遞和深淺複製都是資料複製的操作。所以兩者受到的約束也是相同的,也就要遵循變數讀取的規則。

本文是陳少棠原創,收錄在《齊雲札記》,轉載請標明原作。

Top