面试题答案
一键面试变量提升变化
- 严格模式下表现:
- 在非严格模式中,变量声明会被提升到函数作用域顶部,函数声明不仅提升到函数作用域顶部,还会提升到全局作用域顶部。例如:
function nonStrict() {
console.log(a); // undefined
var a = 1;
}
nonStrict();
- 而在严格模式下,变量声明依然会提升,但未声明的变量直接使用会抛出
ReferenceError
。例如:
function strict() {
'use strict';
console.log(a); // ReferenceError: a is not defined
var a = 1;
}
strict();
- 性能陷阱:变量提升可能导致代码逻辑混乱,在复杂代码中难以理解执行顺序,间接影响维护和性能优化。因为代码执行路径不清晰,可能导致不必要的重复计算或错误的变量访问。
- 解决方案:始终在作用域顶部声明变量,避免依赖变量提升。这样代码执行顺序更清晰,便于维护和性能优化。例如:
function strict() {
'use strict';
var a;
console.log(a); // undefined
a = 1;
}
strict();
闭包使用
- 严格模式下表现:闭包在严格模式下行为基本不变,但由于严格模式对变量使用的限制更严格,闭包内变量访问遵循更清晰的规则。例如:
function outer() {
'use strict';
var x = 1;
return function inner() {
return x;
};
}
var closure = outer();
console.log(closure()); // 1
- 性能陷阱:闭包可能导致内存泄漏。因为闭包会保持对外部作用域变量的引用,如果闭包长时间存在,外部作用域变量无法被垃圾回收机制回收。例如在一个循环中创建大量闭包,每个闭包都引用外部循环变量,可能导致内存消耗不断增加。
function createClosures() {
var closures = [];
for (var i = 0; i < 1000; i++) {
closures.push(function () {
return i;
});
}
return closures;
}
var allClosures = createClosures();
- 解决方案:
- 减少不必要的闭包使用。如果只是需要访问外部变量的值,而不需要长期保持引用,可以将值作为参数传递给函数,而不是创建闭包。
- 及时释放闭包引用。例如,在不再需要闭包时,将其赋值为
null
,使垃圾回收机制能够回收相关内存。
实际项目场景举例
在一个前端单页应用(SPA)项目中,使用模块化开发。假设模块 A
中定义了一个函数 fetchData
,在这个函数内部创建了闭包用于处理异步数据返回。
// 模块A
function fetchData() {
'use strict';
var data = [];
return function (newData) {
data.push(newData);
return data;
};
}
var dataHandler = fetchData();
// 模拟异步获取数据
setTimeout(() => {
dataHandler({ key: 'value' });
console.log(dataHandler());
}, 1000);
这里闭包 dataHandler
长期持有对 data
的引用。如果在应用中频繁调用 fetchData
创建新的闭包,可能导致内存占用不断增加。优化方案可以是在数据处理完成后,及时释放闭包引用,如 dataHandler = null;
,这样当不再需要该闭包时,垃圾回收机制可以回收相关内存,提升性能。同时,在声明变量时遵循在作用域顶部声明的原则,避免变量提升带来的潜在问题。