JavaScript:物件傳參考特性(Pass by Reference)
4.5k 字,約 5 分鐘
文章目錄
Javascript 型別說明
JS 的型別大致可分為原始型別(Primitive Types)及物件(Object)兩種
- 原始型別(Primitive Types):傳值(Pass by value)
- 本身不可變
- 物件(Object):傳參考(Pass by reference)
- 本身可變
原始型別(Primitive Types)
- Number
- 整數
- 含小數點
- Infinity(無窮大)
- -Infinity(負無窮大)
- NaN(Not A Number)--->不是數值
- BigInt
- String
- Boolean
- true
- false
- Undefined
- Null
- Symbol
- 宣告方式如下
// ↓數字
let num = 42;
// ↓字串
let str = "Hello, World!";
// ↓布林
let isTrue = true;
let isFalse = false;
// ↓未定義
let undefinedVar;
// ↓空值
let nullVar = null;
// ↓符號
let sym = Symbol("uniqueSymbol");
物件資料(Object data)
- 物件 (Object)
- 陣列 (Array)
- 函數 (Function)
// ↓物件 (Object)
let person = {
name: "John",
age: 30,
isStudent: false
};
// ↓陣列 (Array)
let fruits = ["apple", "orange", "banana"];
// ↓函數 (Function)
function greet(name) {
console.log("Hello, " + name + "!");
}
javascript-原始型別-傳值(Pass by value)
- 傳遞原始型別的值時,是按值傳遞的。函數接收的是原始值的一個複本,對這個複本的修改不會影響原始值。
let a = 100
let b = a
b = 200
console.log(a)
顯示如下:
100
javascript-物件-傳參考(Pass by reference)
- 當傳遞物件(Object)或陣列(Array)等引用型別的值時,函數接收的是物件或陣列的參考,對這個參考的修改會影響原始物件或陣列。
let a = {"food": "apple"}
let b = a
b.food = "banana"
console.log(a)
顯示如下:
{ food: 'banana' }
淺拷貝(Shallow copy)
- 只拷貝被複製物件的第一層屬性,而不是整個物件及其嵌套的屬性。換句話說,淺拷貝創建了一個新的物件,並將原始物件的直接屬性複製到新的物件中,但對於原始物件中的物件(如物件中的物件),它們仍然是引用,而不是被複製的。
- 成功複製第一層物件的屬性,且彼此互不影響。
let a = { "food": "apple" }
let b = { ...a }
b.food = "banana"
console.log("a變數= ", a)
console.log("b變數= ", b)
顯示如下:
a變數= { food: 'apple' }
b變數= { food: 'banana' }
- 物件中的物件因為指向同一記憶體位址,因此彼此變動會連動。
let a = { "food": "apple", obj : {"feeling": "happy"} }
let b = { ...a }
a.obj.feeling = "sad"
console.log("a變數= ", a)
console.log("b變數= ", b)
顯示如下:
a變數= { food: 'apple', obj: { feeling: 'sad' } }
b變數= { food: 'apple', obj: { feeling: 'sad' } }
淺拷貝的方式
...展開運算子(Spread operator)
- 上面的案例即是採用展開運算子
使用 Object.assign()的方法
const originalObject = { a: 1, b: { c: 2 } };
const shallowCopiedObject = Object.assign({}, originalObject);
shallowCopiedObject.a = 2
shallowCopiedObject.b.c = 100000
console.log("originalObject", originalObject)
console.log("shallowCopiedObject", shallowCopiedObject)
顯示如下:
originalObject { a: 1, b: { c: 100000 } }
shallowCopiedObject { a: 2, b: { c: 100000 } }
陣列能夠使用 slice 的方法
const originalArray = [1, [2, 3], 4];
const shallowCopiedArray = originalArray.slice();
shallowCopiedArray[0] = 'X1';
shallowCopiedArray[1][0] = 'X2';
console.log("originalArray", originalArray);
console.log("shallowCopiedArray", shallowCopiedArray);
顯示如下:
originalArray [ 1, [ 'X2', 3 ], 4 ]
shallowCopiedArray [ 'X1', [ 'X2', 3 ], 4 ]
手動複製物件中其中一層資料
let a = { "food": "apple", obj: { "feeling": "happy" } }
let b = { "food": a.food, obj: a.obj }
console.log("改變前a", a)
console.log("改變前b", b)
b.food = "banana"
b.obj.feeling = "sad"
console.log("------------")
console.log("改變後a", a)
console.log("改變後b", b)
顯示如下
改變前a { food: 'apple', obj: { feeling: 'happy' } }
改變前b { food: 'apple', obj: { feeling: 'happy' } }
------------
改變後a { food: 'apple', obj: { feeling: 'sad' } }
改變後b { food: 'banana', obj: { feeling: 'sad' } }
深拷貝(Deep Copy)
- 是指創建一個新的物件,並且這個新物件的所有屬性的值都是原始物件相對應屬性值的複本。深拷貝會遞迴地複製原始物件及其所有嵌套的物件,使得新的物件和原始物件在記憶體中獨立存在,修改其中一個物件不會影響另一個。
深拷貝的方式
使用 JSON.parse() 和 JSON.stringify()
const originalObject = { a: 1, b: { c: 2 } };
const deepCopiedObject = JSON.parse(JSON.stringify(originalObject));
deepCopiedObject.a = 200
deepCopiedObject.b.c = 4000
console.log("originalObject", originalObject)
console.log("deepCopiedObject", deepCopiedObject)
顯示如下:
originalObject { a: 1, b: { c: 2 } }
deepCopiedObject { a: 200, b: { c: 4000 } }
需注意使用此方式會有些意外情況如下
- undefined:undefined 的值會在序列化過程中完全丟失,包括包含 undefined 值的鍵本身。
- NaN:NaN 會被強制轉換成 null。
- Infinity 和-Infinity:這兩個特殊的數字值會被強制轉換成 null。
- 正則表達式(RegExp):正則表達式會被強制轉換為空物件
- 日期(Date):日期會被轉換成對應的字符串形式。
- 函數(Function):函數是無法被序列化的,它們會被忽略。
- 符號 Symbol 會被忽略,不會被序列化
const originalData = {
undefinedValue: undefined,
notANumberValue: NaN,
infinityValue: Infinity,
regExpValue: /.*/,
dateValue: new Date('1999-12-31T23:59:59'),
functionValue: function() {},
symbolValue: Symbol('uniqueSymbol')
};
const faultyClonedData = JSON.parse(JSON.stringify(originalData));
console.log("undefineValue", faultyClonedData.undefinedValue);
console.log("NaNValue", faultyClonedData.notANumberValue);
console.log("InfinityValue", faultyClonedData.infinityValue);
console.log("regExpValue", faultyClonedData.regExpValue);
console.log("dateValue", faultyClonedData.dateValue);
console.log("function", faultyClonedData.functionValue);
console.log("symbolValue", faultyClonedData.symbolValue);
顯示如下
undefineValue undefined
NaNValue null
InfinityValue null
regExpValue {}
dateValue 1999-12-31T15:59:59.000Z
function undefined
symbolValue undefined
使用第三方庫(例如 Lodash)
const _ = require('lodash');
const originalObject = { a: 1, b: { c: 2 } };
const deepCopiedObject = _.cloneDeep(originalObject);
deepCopiedObject.a = 30
deepCopiedObject.b.c = 4000
console.log("originalObject", originalObject)
console.log("deepCopiedObject", deepCopiedObject)
顯示如下:
originalObject { a: 1, b: { c: 2 } }
deepCopiedObject { a: 30, b: { c: 4000 } }
留言
留言使用 GitHub 帳號登入(Giscus),留言會存在 GitHub Discussions。