JS中的变量传递方式&变量的拷贝

31 阅读2分钟

变量传递的方式

在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(红框) result.png

深拷贝
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