JavaScript 的參數傳遞
- 每個宣告的變數的值(value)都會儲存在不同的記憶體空間
- 使用容量較小,原始型別的資料儲存在 Stack 內
- 複製變數時,會完全複製一份新的「值 (value)」
let a = 6
let b = a
a = 9
console.log(b) // 6
宣告的變數 | 儲存的值 | 記憶體空間 |
---|
a | 6 | 空間 A |
b | 6 | 空間 B |
let a = 6
let b = a
console.log(a == b) //true
console.log(a === b) //true
- 函式接收到的參數值是原始值的一個複製
- 當函式修改參數的值時,原始值不會被改變
let age = 18
function increase(age) {
age++
}
increase(age)
console.log(age) // 18;
- 儲存資料值所在的記憶體位置的地址 (address)
- 物件類別的資料通常較為複雜,佔用記憶體容量較大,會儲存在 Heap 內
- 複製變數時,是複製一份新的「地址 (address)」,並非複製值 (value)
- 注意重點: 原物件是否會被修改
//因為是儲存記憶體位置,所以用const宣告的陣列可以被修改
const arr = [55, 66]
arr.push(77)
//值會被變更
console.log(arr) // [55,66,77]
// object example
//x有一個記憶體位址 0x01 指向儲存的值 {value:10}
let x = { value: 10 }
//y有同一個記憶體位址 0x01 指向相同的值
let y = x
x.value = 20
console.log(x) // {value: 20}
console.log(y) // {value: 20}
//array example
let animals = ['zebra', 'bear', 'deer']
let animals2 = animals
animals2.push('lion')
console.log(animals) // ['zebra','bear','deer','lion']
宣告的變數 | 儲存的值 |
---|
x | 記憶體位址 0x01 |
y | 記憶體位址 0x01 |
animals | 記憶體位址 0x02 |
animals2 | 記憶體位址 0x02 |
記憶體位址 | 值 |
---|
0x01 | { value: 20} |
0x02 | 'zebra' ,'bear', 'deer', 'lion' |
- 使用 == , === 比較時,是比較記憶體位址是否相同
//記憶體位址不同
console.log([] == []) //false
console.log([10] == [10]) //false
console.log(['hello', 'bye'] === ['hello', 'bye']) // false
//有相同的值和記憶體位址
let arr1 = [1, 2, 3] //0x01
let arr2 = arr1 //0x01
console.log(arr1 == arr2) //true
console.log(arr1 === arr2) //true
//有相同的值,但記憶體位址不同
let arr3 = [4, 5, 6] //0x01
let arr4 = [4, 5, 6] //0x02
console.log(arr3 == arr4) //false
console.log(arr3 === arr4) //false
- 因為物件類別有 call by reference 特性,如果不想修改原物件,可以使用一些方法來複製一份
- 例如想要新增物件屬性,但希望保留原本的物件資料時
- 只複製物件第一層屬性 (primitive type)
- 修改物件第一層屬性的值不會影響原物件
- 若有第二層以上結構時 (reference type),位址仍然相同,指向同樣的值
- 修改物件第二層屬性的值會影響原物件
- 方法 1:展開運算子 (Spread Operator)
//範例:複製物件
const jacket = { brand: 'UNIQLO', color: 'navy' }
const Jacket2 = { ...jacket }
console.log(newJacket) // { brand: 'UNIQLO', color: 'navy' }
//範例:複製陣列
const dinner = ['pizza', 'hamburger', 'sandwich']
const dinner2 = [...dinner]
console.log(dinner2) // ['pizza','hamburger','sandwich']
- 方法 2: Object.assign()
//語法
Object.assign(target, ...sources)
//範例:複製物件
const obj = { a: 1 }
const copy = Object.assign({}, obj)
console.log(copy) // { a: 1 }
- 方法 3: Array.prototype.slice()
- 會回傳一個新陣列物件
- 為原陣列選擇之 begin 至 end(不含 end)部分的淺拷貝(shallow copy)
- 原本的陣列不會被修改
//語法
arr.slice([begin[, end]])
const drinks = ['tea','coke','milk']
//寫法1: 不給參數,會全部複製一份
const mydrinks = drinks.slice()
console.log(mydrinks) // ['tea', 'coke', 'milk']
//寫法2:小括號內放0,結果同上
const mydrinks = drinks.slice(0)
console.log(mydrinks) // ['tea', 'coke', 'milk']
- 範例
- 如果物件內有 reference type(Object,Array...),是複製其位址,仍指向相同的值
//example1
//改變第一層屬性的值,不影響原物件
const car1 = {
brand: 'tesla',
color: 'white',
detail: {
model: 'ModelX',
year: '2023'
}
}
const car2 = Object.assign({}, car1)
car2.color = 'black'
console.log(car1)
/*{
brand: 'tesla',
color: 'white',
detail: { model: 'ModelX', year: '2023' }
}*/
console.log(car2)
/*{
brand: 'tesla',
color: 'black',
detail: { model: 'ModelX', year: '2023' }
}*/
//example2
//改變第二層物件的值,連原物件也一起改變
let car2 = Object.assign({}, car1)
car2.detail.model = 'Model3'
//因為car1和car2內的detail共享同個位址
//當改變car2的detail內model的值時,car1也會同樣被改變
console.log(car1)
/*{
brand: 'tesla',
color: 'white',
detail: { model: 'Model3', year: '2023' }
}*/
console.log(car2)
/*{
brand: 'tesla',
color: 'white',
detail: { model: 'Model3', year: '2023' }
}*/
- 深度複製指定物件,操作新物件不影響原物件
- 兩者指向不同記憶體位址
方法 1: 使用JSON.stringify/parse
//深拷貝方法 JSON.stringify/parse
const myBand = {
name: 'The Strokes',
members: {
vocal: 'Julian',
guitarist1: 'Albert',
guitarist2: 'Nick',
bassist: 'Nikolai',
drummer: 'Fabrizio'
}
}
//使用JSON.stringify將myBand轉成字串
//再透過JSON.parse將字串轉回物件
const newBand = JSON.parse(JSON.stringify(myBand))
console.log(myBand === newBand) // false
newBand.members.vocal = 'Kurt'
// myBand不會被改變
console.log(myBand)
/*{
name: 'The Strokes',
members: {
vocal: 'Julian',
guitarist1: 'Albert',
guitarist2: 'Nick',
bassist: 'Nikolai',
drummer: 'Fabrizio'
}
}*/
console.log(newBand)
/*{
name: 'The Strokes',
members: {
vocal: 'Kurt',
guitarist1: 'Albert',
guitarist2: 'Nick',
bassist: 'Nikolai',
drummer: 'Fabrizio'
}
}*/
方法 2: 使用structuredClone
const myBand = {
name: 'The Strokes',
members: {
vocal: 'Julian',
guitarist1: 'Albert',
guitarist2: 'Nick',
bassist: 'Nikolai',
drummer: 'Fabrizio'
}
}
const yourBand = structuredClone(myBand)
console.log(yourBand === myBand) // false
yourBand.members.drummer = 'Ringo'
console.log(myBand)
/*{
name: 'The Strokes',
members: {
vocal: 'Julian',
guitarist1: 'Albert',
guitarist2: 'Nick',
bassist: 'Nikolai',
drummer: 'Fabrizio'
}
}*/
console.log(yourBand)
// {
// "name": "The Strokes",
// "members": {
// "vocal": "Julian",
// "guitarist1": "Albert",
// "guitarist2": "Nick",
// "bassist": "Nikolai",
// "drummer": "Ringo"
// }
// }