JavaScript 中,值的傳遞行為分成兩種:「傳值與傳址」,決定這兩種傳遞方式的就是「型別」。
基本型別用傳值、物件型別用傳址。
基本型別用傳值,所以先來看看基本型別有哪些:
string
number
boolean
null
undefined
。當值為基本型別時,賦值是使用複製的方式,也就是只拷貝它的值。
const a = 1;
const b = a;
console.log(a === b); // true
上面的 ===
是比較兩個值是否相等。這種純粹只是複製值的方式、且不影響到到對方的行為,稱為 傳值。
所以當我們修改其中一邊:
const a = 1;
let b = a;
b = 2
console.log(a); // 1
console.log(a === b); // false
另一個是不影響的。
物件型別就不一樣了,當我們賦值時,會引用該地址來指向物件。
const obj = { a: 1 };
const obj2 = { a: 1 };
console.log(obj === obj2); //false
雖然兩個 obj
的值相同,但物件的比較是看記憶體位置是否相同,所以為 false
。
因為記憶體位置相同,所以當我們嘗試修改其中一個物件時:
const obj = { a: 1 };
const obj2 = obj;
obj2.a = 2
console.log(obj.a); // 2
console.log(obj2.a); // 2
兩個 obj
的 a
都變成了 2。
如果物件在函式中被重新賦值,那外部物件則不影響。
const person = { name: 'Peter' };
function changeName(obj){
obj = { name: 'Tim' }
}
changeName(person)
console.log(person) // { name: 'Peter' }
如果不是重新賦值,則變成傳址。
const person = { name: 'Peter' };
function changeName(obj){
obj.name = 'Tim'
}
changeName(person)
console.log(person) // { name: 'Tim' }
除了傳值傳址外,我們也常常會聽到淺拷貝(Shallow copy)與深拷貝(Deep copy)兩個詞,其實我們已經知道淺拷貝是什麼了,就是上面文章提到的傳址,只會參考同一個物件。
那如果我想要複製一個全新的物件勒? 這時候就需要深拷貝。
我們可以透過 JSON.stringify
及 JSON.parse
建立出新的物件。
const obj1 = {
name: 'Peter',
age: 18
}
const obj2 = JSON.parse(JSON.stringify(obj1))
obj2.name = 'Tim' // 修改 obj2
console.log(obj1.name) // obj1 不會跟著變,印出 Peter
最後再補充一下定義: