小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
1. 对象的引用、浅拷贝、深拷贝
1.1 对象的引用赋值
我们知道,对象是引用类型(JavaScript、Java 等语言中称为引用类型,而在 C、C++ 等语言中称为指针),也就是说我们在用对象给某个变量赋值时,实际上是把对象的引用(是一个内存地址)赋值给了该变量,之后我们就说这个变量引用了这个对象(其实就是一个指针,指向了这个对象的内存地址)。
// 对象是引用类型
const info = { name: 'zhj', age: 20 };
const obj = info;
info.name = 'wy';
console.log(obj.name); // wy
上面这段代码在内存中的表现如下:
1.2 浅拷贝
浅拷贝的方法有很多,我们以 Object.assign() 方法为例:
const info = { name: 'zhj', age: 20 };
// 即把第二个参数 info 对象中所有的属性拷贝一份放到第一个参数对象 {} 中,然后将第一个参数对象作为返回值返回
const obj = Object.assign({}, info);
info.name = 'wy';
console.log(obj.name); // zhj
上面这段代码在内存中的表现如下:
但是,假如上面的 info 对象中不全是基本类型的属性,还有对象类型的属性,那么再对源对象的该对象属性中的属性(info.friend.name)做修改,也会影响拷贝出的对象的该对象属性中的属性值(obj.friend.name),它们的值是一样的,因为它们引用着堆内存中的同一个对象(info 和 obj 的 friend 属性引用的那个对象):
const info = {
name: 'zhj',
age: 20,
friend: {
name: 'ls',
height: 1.88
}
};
const obj = Object.assign({}, info);
info.name = 'wy';
console.log(obj.name); // zhj
info.friend.name = 'ww';
console.log(obj.friend.name); // ww
上面这段代码在内存中的表现如下:
因此,浅拷贝只是将对象的第一层属性进行了拷贝,而对更深层的属性其实是没有做拷贝的。
1.3 深拷贝
深拷贝的方法也有很多,我们拿一种原生的方式(使用 JSON 的两个方法)为例:
const info = {
name: 'zhj',
age: 20,
friend: {
name: 'ls',
height: 1.88
}
};
// 先通过 JSON.stringify() 方法把对象转成字符串,在通过 JSON.parse() 方法把字符串还原成对象。还原的时候会在内存中生成一个新的对象,和原来的对象没有任何关系。
const obj = JSON.parse(JSON.stringify(info));
info.name = 'wy';
console.log(obj.name); // zhj
info.friend.name = 'ww';
console.log(obj.friend.name); // ls
上面这段代码在内存中的表现如下:
因此,深拷贝会对每一层的对象都进行拷贝(拷贝一份新的,而不是使用原来的)。
1.4 使用第三方库的浅/深拷贝方法
除了使用 JS 原生的方式实现浅拷贝或深拷贝,我们还可以使用 lodash 库提供的浅拷贝、深拷贝方法:
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
const info = {
name: 'zhj',
age: 20,
friend: {
name: 'ls',
height: 1.88
}
};
// const obj = Object.assign({}, info);
// 使用 lodash 的 clone() 方法进行浅拷贝
const obj = _.clone(info);
info.name = 'wy';
console.log(obj.name); // zhj
info.friend.name = 'ww';
console.log(obj.friend.name); // ww
const info = {
name: 'zhj',
age: 20,
friend: {
name: 'ls',
height: 1.88
}
};
// const obj = JSON.parse(JSON.stringify(info));
// 使用 lodash 的 cloneDeep() 方法进行浅拷贝
const obj = _.cloneDeep(info);
info.name = 'wy';
console.log(obj.name); // zhj
info.friend.name = 'ww';
console.log(obj.friend.name); // ls
2. JS 逻辑判断中的隐式转化
逻辑判断时,如果是一个内容为数字的字符串和一个数字进行比较,会隐式的自动将这个内容为数字的字符串转化为 number 类型后再进行比较:
const score = "100";
// 字符串 "100" 和 number 类型的 90 比较,会先将 "100" 转换为 number 类型的 100,再拿 100 和 90 比较
if (score > 90) { // true
console.log('优秀');
}