面试题答案
一键面试问题原因分析
在JavaScript模块化系统中,模块之间共享状态可能会导致问题。模块A导出的func
函数依赖其内部变量,当模块B导入func
后,模块A中的内部变量被意外修改,由于func
函数在执行时会访问这个已经被修改的变量,从而导致运行异常。这是因为JavaScript模块在导入导出时,对于基本类型变量是值传递,而对于引用类型变量(如对象、数组等)是引用传递,很可能是对引用类型变量进行了意外修改。
解决方案及优缺点
方案一:使用闭包封装
- 实现方式:在模块A中,将
func
函数及依赖的内部变量通过闭包封装起来。例如:
// 模块A
let internalVariable = 'initial value';
function func() {
return `The value is: ${internalVariable}`;
}
function createFunc() {
return func;
}
export default createFunc();
- 优点:闭包可以很好地隔离内部变量,防止外部直接访问和修改,从而确保
func
函数使用的是闭包内定义的变量状态,不受外部干扰。 - 缺点:增加了一层函数调用封装,代码的复杂度略有提升,并且如果闭包内引用的变量占用内存较大,可能会导致内存消耗增加。
方案二:使用常量或冻结对象
- 实现方式:
- 使用常量:在模块A中,将依赖的变量定义为常量(
const
),如果是对象类型,可以使用Object.freeze
冻结对象。例如:
- 使用常量:在模块A中,将依赖的变量定义为常量(
// 模块A
const internalVariable = 'initial value';
export function func() {
return `The value is: ${internalVariable}`;
}
- **冻结对象**:如果`internalVariable`是对象类型:
// 模块A
let internalObj = { value: 'initial value' };
Object.freeze(internalObj);
export function func() {
return `The value is: ${internalObj.value}`;
}
- 优点:
- 使用常量:语法简单直观,能够有效防止变量被意外重新赋值,保证
func
函数依赖的变量值稳定。 - 冻结对象:可以防止对象的属性被意外修改,对于复杂数据结构比较适用。
- 使用常量:语法简单直观,能够有效防止变量被意外重新赋值,保证
- 缺点:
- 使用常量:如果后续有修改需求,代码修改成本较高,因为常量一旦定义就不能重新赋值。
- 冻结对象:只能防止对象自身属性的直接修改,但对于对象内部嵌套对象的属性修改无法阻止,并且不能向冻结对象添加新属性。