变量传递的方式
在js中变量传递的方式有两种,一种是值传递(pass by value),一种是引用传递(pass by reference)
值传递
对于基本数据类型,JavaScript使用值传递。这就是说,当把一个变量赋值给另一个变量时,实际上创建的是这个值的副本。对这个副本的修改不会影响原来的值。
let a = 10;
let b = a; // 复制了 a 的值
b = 20; // 修改 b,不会影响 a
console.log(a); // 输出 10
console.log(b); // 输出 20
引用传递
对于复杂的数据类型,JavaScript使用引用传递。这就是说,当把一个对象类型的变量赋值给另一个变量时,实际上是复制的这个对象的引用。对这个引用的修改会影响原来的值。
let obj1 = { name: 'Alice' };
let obj2 = obj1; // 复制了 obj1 的引用
obj2.name = 'Bob'; // 修改 obj2 的属性
console.log(obj1.name); // 输出 'Bob'
console.log(obj2.name); // 输出 'Bob'
拷贝的实现
浅拷贝
使用 hasOwnProperty 方法确保只复制对象自身的属性(不包括继承的属性)。
function shallowCopy(obj) {
if (typeof obj !== "object" || obj === null) return obj;
const copy = Array.isArray(obj) ? [] : {};
// 遍历原对象的属性并将其复制到新对象中
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
copy[key] = obj[key];
}
}
return copy;
}
let p = {
name: "nothing",
a: {
b: {
c: 1,
},
d: 2,
},
};
let cp = shallowCopy(p);
let assignObj = Object.assign({}, p);
console.log("p", p);
console.log("p.a.b.c before", p.a.b.c);
console.log("cp.a.b.c before", cp.a.b.c);
console.log("assignObj.a.b.c before", assignObj.a.b.c);
cp.a.b.c = 10;
console.log("----- assign cp.a.b.c = 10 -----");
console.log("p.a.b.c after", p.a.b.c);
console.log("cp.a.b.c", cp.a.b.c);
console.log("assignObj.a.b.c", assignObj.a.b.c);
从下图中可以看到结果
在赋值的前后
直接取对象深层次的数据,p.a.b.c都是按照逻辑来的,赋值前没有改变1,在赋值后改变了10
如果是在赋值前,直接打印整个对象的值,可以看到,其中的 p.a.b.c 还是为10(红框)
深拷贝
function deepCopy(obj) {
if (obj === null || typeof obj !== 'object') return obj
if (Array.isArray(obj)) {
const copy = []
for (let i = 0; i < obj.length; ++i) {
copy[i] = deepCopy(obj[i])
}
return copy
}
const copy = {}
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
copy[key] = deepCopy(obj[key])
}
}
return copy
}
const obj = { a: 1, b: { c: 2 } }
const shallowObj = Object.assign({}, obj)
const deepObj = deepCopy(obj)
obj.b.c = 3
console.log(deepObj.b.c) // 2