在JavaScript中,“引用变量”通常指的是一个变量,它存储的是另一个对象(如数组、函数、日期等)的内存地址,而不是直接存储值本身。这意味着,当你改变引用变量所指向的对象的属性时,所有引用该对象的其他变量也会看到这些改变。
原因:因为这些变量都引用同一个对象。当你通过一个引用修改对象的属性时,实际上是在修改内存中那个对象的属性,因此所有引用该对象的变量都会看到这些改变。
解决方法:如果你想要避免这种情况,可以在修改前创建对象的副本(深拷贝),然后修改副本。
let obj1 = { a: 1 };
let obj2 = { ...obj1 }; // 使用扩展运算符创建浅拷贝
obj2.a = 2;
console.log(obj1.a); // 输出1,obj1不受影响
解决方法:可以使用typeof
运算符和instanceof
运算符来判断。对于基本类型,typeof
可以直接判断;对于引用类型,typeof
通常返回"object"
(除了函数返回"function"
),这时可以使用instanceof
或者Object.prototype.toString.call()
来进一步判断。
console.log(typeof 123); // "number"
console.log(typeof "hello"); // "string"
console.log(typeof {}); // "object"
console.log({} instanceof Object); // true
console.log(Object.prototype.toString.call([])); // "[object Array]"
深拷贝:创建一个新的对象,并递归地复制原对象的所有属性以及属性所引用的对象(如果属性也是对象)。这样,新对象和原对象完全独立。
浅拷贝:只复制对象的顶层属性,如果属性也是对象,则复制的是引用而不是对象本身。
解决方法:可以使用JSON方法、扩展运算符、Object.assign()
等方法来实现浅拷贝;使用structuredClone()
方法或者第三方库(如lodash的_.cloneDeep()
)来实现深拷贝。
// 浅拷贝示例
let obj1 = { a: 1, b: { c: 2 } };
let obj2 = { ...obj1 };
obj2.b.c = 3;
console.log(obj1.b.c); // 输出3,因为obj2.b和obj1.b引用同一个对象
// 深拷贝示例(使用structuredClone)
let obj3 = structuredClone(obj1);
obj3.b.c = 4;
console.log(obj1.b.c); // 输出3,obj3.b是obj1.b的深拷贝,它们是完全独立的对象
注意:structuredClone()
是较新的API,可能不在所有环境中都可用。在不支持的环境中,可以使用JSON方法或者第三方库来实现深拷贝。
领取专属 10元无门槛券
手把手带您无忧上云