面试题答案
一键面试基本类型变量
- 内存分配:基本类型(如
number
、string
、boolean
、null
、undefined
、symbol
)的值是直接存储在栈内存中的。当声明并初始化一个基本类型变量时,栈内存会为其分配一个固定大小的空间来存储值。例如:
let num = 10;
这里num
变量在栈内存中分配了存储10
这个数字所需的空间。
2. 内存释放:当基本类型变量超出其作用域时,栈内存会自动释放该变量所占用的空间。例如在函数内部声明的基本类型变量,当函数执行结束,变量的作用域结束,其占用的栈内存空间就会被释放。
引用类型变量
- 内存分配:引用类型(如
Object
、Array
、Function
等)的值存储在堆内存中。当声明并初始化一个引用类型变量时,栈内存会为变量分配一个空间来存储指向堆内存中实际对象的地址。例如:
let obj = {name: 'John'};
这里obj
变量在栈内存中存储了指向堆内存中包含{name: 'John'}
对象的地址,而对象本身存储在堆内存中。
2. 内存释放:引用类型变量所占用的堆内存空间,在没有任何变量引用它时,会被JavaScript的垃圾回收机制(通常采用标记清除算法)回收。当一个对象在堆内存中没有任何变量持有其引用时,垃圾回收器会标记该对象为可回收,在下一次垃圾回收周期中释放其占用的堆内存空间。
循环引用变量及影响
- 循环引用:循环引用是指两个或多个对象相互引用,形成一个封闭的引用环。例如:
function createCircularReference() {
let obj1 = {};
let obj2 = {};
obj1.other = obj2;
obj2.other = obj1;
return {obj1, obj2};
}
这里obj1
和obj2
相互引用。
2. 对内存的影响:在早期的JavaScript引擎中,循环引用可能会导致内存泄漏,因为垃圾回收机制可能无法正确识别这些相互引用但实际上不再被外部代码使用的对象,从而无法释放它们占用的堆内存空间,随着时间推移,会导致内存占用不断增加。
3. 避免内存泄漏:
- 手动解除引用:在对象不再需要时,手动将相互引用的变量设置为null
,打破循环引用。例如:
let {obj1, obj2} = createCircularReference();
// 使用完obj1和obj2后
obj1.other = null;
obj2.other = null;
obj1 = null;
obj2 = null;
- **现代引擎优化**:现代的JavaScript引擎(如V8)已经对垃圾回收机制进行了优化,能够检测并处理循环引用,即使存在循环引用,在没有外部引用时,对象也能被正确回收,降低了内存泄漏的风险。但手动解除引用仍然是一个良好的编程习惯,可提高代码的可维护性和性能。