javascript傳遞參數如果是object的話,是按值傳遞還是按引用傳遞?

先看看這段代碼的輸出結果:

function test(person) {
  person.age = 26
  person = {
    name: 'huahua',
    age: 90
  }
  return person
}
const p1 = {
  name: 'cc',
  age: 11
}
const p2 = test(p1)
console.log(p1) // -> ?
console.log(p2) // -> ?

結果:

p1: {name: 'cc', age: 26}
p2: {name: 'huahua', age: 90}

原因:

在函數傳參你的時候傳遞的是對象在堆中的內存地址,test函數中的實參person是p1對象的內存地址,通過person.age = 26確實改變了p1的值,但隨後person變成了另外一塊內存空間的地址,並且在最後將這另外一份內存空間的地址返回賦給了p2

對於此問題涉及到JS相關的知識:

數據類型

在 javascript 中數據類型可以分爲兩類:
原始數據類型值 primitive type,比如Undefined,Null,Boolean,Number,String,Symbol。
引用類型值,也就是對象類型 Object type,比如Object,Array,Function,Date等。
聲明變量時不同的內存分配:

  • 原始值:存儲在棧(stack)中的簡單數據段,也就是說,它們的值直接存儲在變量訪問的位置。這是因爲原始類型佔據的空間是固定的,所以可以將他們存儲在較小的內存區域-棧中。這樣存儲便於迅速查詢變量的值。
  • 引用值:存儲在堆(heap)中的對象,也就是說,存儲在變量處的值是一個指針(point),指向存儲對象的內存地址。這是因爲:引用值的大小會改變,所以不能把它放在棧中,否則會降低變量查詢的速度。相反,放在變量的棧空間中的值是該對象存儲在堆中的地址。地址的大小是固定的,所以把它存儲在棧中對變量性能無任何負面影響。

在javascript中是不允許直接訪問保存在堆內存中的對象的,所以在訪問一個對象時,首先得到的是這個對象在堆內存中的地址,然後再按照這個地址去獲得這個對象中的值,這就是傳說中的按引用訪問。而原始類型的值則是可以直接訪問到的。

複製變量時的不同
  • 原始值:在將一個保存着原始值的變量複製給另一個變量時,會將原始值的副本賦值給新變量,此後這兩個變量是完全獨立的,他們只是擁有相同的value而已。
  • 引用值:在將一個保存着對象內存地址的變量複製給另一個變量時,會把這個內存地址賦值給新變量,也就是說這兩個變量都指向了堆內存中的同一個對象,他們中任何一個作出的改變都會反映在另一個身上。(這裏要理解的一點就是,複製對象時並不會在堆內存中新生成一個一模一樣的對象,只是多了一個保存指向這個對象指針的變量罷了)
參數傳遞的不同

首先我們應該明確一點:ECMAScript中所有函數的參數都是按值來傳遞的。但是爲什麼涉及到原始類型與引用類型的值時仍然有區別呢,還不就是因爲內存分配時的差別。 (我對比了一下,這裏和複製變量時遵循的機制完全一樣的嘛,你可以簡單地理解爲傳遞參數的時候,就是把實參複製給形參的過程)

  • 原始值:只是把變量裏的值傳遞給參數,之後參數和這個變量互不影響。
  • 引用值:對象變量它裏面的值是這個對象在堆內存中的內存地址,因此它傳遞的值也就是這個內存地址,這也就是爲什麼函數內部對這個參數的修改會體現在外部的原因了,因爲它們都指向同一個對象。上圖:
    在這裏插入圖片描述
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章