>> 發文日期 : 2023/8/11
Call by Value 跟 Call by Reference 是個非常重要的基礎觀念,其實我們常常會在開發的過程中踩雷,但是卻不知道原因,所以這邊就要來記錄一下這兩個觀念。
當我們在建立 primitive type 的變數時(數字、字串、布林),假設我把a 指定成一個 primitive type 的時候,a 會在記憶體中存在一個自己的位置。這時候,當我指定另一個變數 b,它的值等同於 a 的時候,b 實際上會建立另一個獨立的記憶體位置,接著再把 a 的值存在這個獨立的記憶體位置。也就是說, a 和 b 其實是存在於兩個不同的記憶體位置,因此彼此並不會乎相干擾影響。
一般我會記住在 Number、String、Boolean的變數型別下,他們就是Call by Value,這也算是比較簡單的想法,從下方的範例我們也可以很清出的看到這個結果,既然都是獨立的變數,不互相影響應該是正常的吧?讓我們看完範例後來看看 Call by Reference。
當我將變數 a 設立成一個Object(或function)時,這時候,一樣會在記憶體中給它一個位置;但是當我建立一個變數 b,並且把變數 b 的值等同於 a 時,這時候並不會再給它一個新的位置,而是一樣指定到物件 a 的位置,實際上是不會有新的東西被建立,變數 a 和 b 都會被指稱到相同的位置,因此,當 a 的值改變的時候 b 的值也會改變,因為它們實際上是指稱到相同的位置。
奇怪!為什麼在Reference的情況下,a的值改變時,b的值也會改變呢?這是因為在Javascript中,Object、Array、Function 這些變數型別都是Call by Reference,可千萬別覺得只有新手才會碰到這個問題,資深工程師們常常一個不注意也都會踩到這個雷,下面有些其他的情境,讓我們來看看。
這個就是比較典型的Call by Reference的情境,那如果?
他們的值不是一樣嗎?為什麼會是false呢?這是因為他們是不同的reference,所以他們的值雖然一樣,但是他們的位置不一樣,所以就會是false。
一般我們比較容易踩雷的都會是在Call by Reference的時候,當我們要複製一個新的Object或Array時,如果我們使用上述的方式,就不是我們所期望複製一個獨立的變數,這裡就要提到另一個觀念,淺拷貝(Shallow copy)跟深拷貝(Deep copy)。
淺拷貝簡單來說他就不是我們希望兩個變數完全獨立的方法,有可能遇到物件只獨立了第一層而沒有獨立到第二層,所以我就只簡單列出一些常見的淺拷貝方法:
排除這些方法,就要重點來分享這次的重點,深拷貝有哪些方式,讓你在開發上避免踩雷: