面试题答案
一键面试Object和Array在内存中的存储结构
- Object:在JavaScript中,对象是通过引用类型存储在内存中的。当创建一个对象时,会在堆内存中分配一块空间来存储对象的属性和值。而在栈内存中,变量名存储的是指向堆内存中该对象的引用地址。例如:
let obj = {name: 'John'};
这里obj
变量存放在栈内存,它指向堆内存中存储{name: 'John'}
的位置。
- Array:数组本质上也是对象,同样在堆内存中存储其元素,栈内存中变量名存储指向堆内存中数组对象的引用。例如:
let arr = [1, 2, 3];
arr
变量在栈内存,指向堆内存中存储[1, 2, 3]
的数组对象。
原型链的作用
- Object:每个对象都有
__proto__
属性,它指向该对象的原型对象。原型对象本身也是一个对象,也有自己的__proto__
属性,这样就形成了一条原型链。当访问对象的属性时,如果对象本身没有该属性,JavaScript引擎会沿着原型链向上查找,直到找到该属性或者到达原型链的顶端(null
)。例如:
let obj = {};
console.log(obj.toString()); // 从原型链上找到toString方法
这里obj
本身没有toString
方法,但通过原型链在Object.prototype
上找到了该方法。
- Array:数组同样具有原型链。数组的原型对象
Array.prototype
定义了许多数组常用的方法,如push
、pop
等。当对数组调用这些方法时,就是通过原型链找到的。例如:
let arr = [];
arr.push(1); // 从Array.prototype上找到push方法
深拷贝和浅拷贝时内存中的变化
- 浅拷贝:浅拷贝只复制对象的第一层属性,对于对象的嵌套属性,只是复制引用地址,而不是递归复制其内部结构。因此,原对象和拷贝对象的嵌套属性会指向同一个内存地址。以
Object.assign
为例:
let originalObj = {
a: 1,
b: {c: 2}
};
let shallowCopy = Object.assign({}, originalObj);
shallowCopy.b.c = 3;
console.log(originalObj.b.c); // 输出 3,说明原对象和浅拷贝对象的嵌套属性指向同一内存地址
- 深拷贝:深拷贝会递归地复制对象的所有层级属性,原对象和拷贝对象在内存中完全独立,互不影响。可以使用
JSON.parse(JSON.stringify())
来实现简单的深拷贝(但它有局限性,不能处理函数、正则等特殊对象):
let originalObj = {
a: 1,
b: {c: 2}
};
let deepCopy = JSON.parse(JSON.stringify(originalObj));
deepCopy.b.c = 3;
console.log(originalObj.b.c); // 输出 2,说明原对象和深拷贝对象相互独立
如果要处理函数、正则等特殊对象,可以使用lodash
库的cloneDeep
方法:
import _ from 'lodash';
let originalObj = {
a: function() {},
b: /abc/
};
let deepCopy = _.cloneDeep(originalObj);