MST

星途 面试题库

面试题:JavaScript变量存储与数据类型:复杂数据类型的原型链与内存

以Object和Array这两种复杂数据类型为例,阐述它们在内存中的存储结构,以及原型链在其中的作用。当对复杂数据类型进行深拷贝和浅拷贝时,内存中的变化是怎样的?请通过代码示例说明。
17.2万 热度难度
编程语言JavaScript

知识考点

AI 面试

面试题答案

一键面试

Object和Array在内存中的存储结构

  1. Object:在JavaScript中,对象是通过引用类型存储在内存中的。当创建一个对象时,会在堆内存中分配一块空间来存储对象的属性和值。而在栈内存中,变量名存储的是指向堆内存中该对象的引用地址。例如:
let obj = {name: 'John'};

这里obj变量存放在栈内存,它指向堆内存中存储{name: 'John'}的位置。

  1. Array:数组本质上也是对象,同样在堆内存中存储其元素,栈内存中变量名存储指向堆内存中数组对象的引用。例如:
let arr = [1, 2, 3];

arr变量在栈内存,指向堆内存中存储[1, 2, 3]的数组对象。

原型链的作用

  1. Object:每个对象都有__proto__属性,它指向该对象的原型对象。原型对象本身也是一个对象,也有自己的__proto__属性,这样就形成了一条原型链。当访问对象的属性时,如果对象本身没有该属性,JavaScript引擎会沿着原型链向上查找,直到找到该属性或者到达原型链的顶端(null)。例如:
let obj = {};
console.log(obj.toString()); // 从原型链上找到toString方法

这里obj本身没有toString方法,但通过原型链在Object.prototype上找到了该方法。

  1. Array:数组同样具有原型链。数组的原型对象Array.prototype定义了许多数组常用的方法,如pushpop等。当对数组调用这些方法时,就是通过原型链找到的。例如:
let arr = [];
arr.push(1); // 从Array.prototype上找到push方法

深拷贝和浅拷贝时内存中的变化

  1. 浅拷贝:浅拷贝只复制对象的第一层属性,对于对象的嵌套属性,只是复制引用地址,而不是递归复制其内部结构。因此,原对象和拷贝对象的嵌套属性会指向同一个内存地址。以Object.assign为例:
let originalObj = {
    a: 1,
    b: {c: 2}
};
let shallowCopy = Object.assign({}, originalObj);
shallowCopy.b.c = 3;
console.log(originalObj.b.c); // 输出 3,说明原对象和浅拷贝对象的嵌套属性指向同一内存地址
  1. 深拷贝:深拷贝会递归地复制对象的所有层级属性,原对象和拷贝对象在内存中完全独立,互不影响。可以使用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);