ES6类访问外部变量异常:构造器调用方法失效原因及解决咨询
问题原因分析
这个问题的核心是变量初始化顺序和暂时性死区导致的,我们来拆解一下实际的执行流程:
假设你的代码运行顺序大致是这样的:
// 1. 先定义Circle类 class Circle{ constructor(){ this.cost = this.calculateCost() // 步骤3:构造器触发calculateCost调用 } showCosts(){ console.log(l.findHeight(100)); // 步骤5:此时l已经完成赋值 } calculateCost(){ console.log(l.findHeight(100)); // 步骤4:此时l还未被赋值 } } // 2. 声明并尝试创建Circle实例赋值给l let l = new Circle(); // 5. 调用实例方法 l.showCosts();
当执行let l = new Circle()时:
- 程序先进入Circle的构造器,立刻调用
this.calculateCost() - 此时
l虽然被let声明了,但还没完成赋值(因为new Circle()的执行结果还没给到l),而let声明的变量在赋值前处于暂时性死区,访问它会得到undefined,自然就会抛出"Cannot read properties of undefined"的错误。
而后续调用l.showCosts()时,l已经被成功赋值为Circle的实例(或者你预期的外部对象),此时访问l.findHeight就能正常执行了。
解决方法
根据不同的场景,你可以选择以下几种解决方案:
方案1:依赖注入(推荐)
把需要的外部对象l作为参数传入Circle的构造器,让类不再依赖外部作用域的变量,代码会更健壮、易维护:
class Circle{ constructor(externalL){ this.externalL = externalL; // 保存传入的外部对象 this.cost = this.calculateCost() } showCosts(){ console.log(this.externalL.findHeight(100)); } calculateCost(){ console.log(this.externalL.findHeight(100)); // 假设这里需要返回计算结果,比如: // return this.externalL.findHeight(100); } } // 先初始化外部对象l let l = new YourLClass(); // 替换成你实际的l对象初始化逻辑 // 把l传入Circle构造器创建实例 let circleInstance = new Circle(l); circleInstance.showCosts();
方案2:延迟初始化逻辑
不在构造器中调用依赖外部变量的方法,而是等外部对象l初始化完成后,手动触发初始化:
class Circle{ constructor(){ // 构造器只做基础初始化,不调用依赖外部的方法 } // 新增专门的成本初始化方法 initCost(){ this.cost = this.calculateCost(); } showCosts(){ console.log(l.findHeight(100)); } calculateCost(){ console.log(l.findHeight(100)); return l.findHeight(100); } } // 1. 先初始化外部对象l let l = new YourLClass(); // 2. 创建Circle实例 let circleInstance = new Circle(); // 3. 此时l已存在,调用初始化方法 circleInstance.initCost(); circleInstance.showCosts();
方案3:提前初始化l(仅适用于全局/作用域提前可初始化场景)
如果l是全局变量或者可以在Circle实例化前完成初始化,直接调整代码顺序即可:
// 1. 先完成l的初始化 let l = new YourLClass(); // 2. 定义Circle类 class Circle{ constructor(){ this.cost = this.calculateCost() // 此时l已经存在,能正常访问 } showCosts(){ console.log(l.findHeight(100)); } calculateCost(){ console.log(l.findHeight(100)); } } // 3. 创建Circle实例 let circleInstance = new Circle(); circleInstance.showCosts();
内容的提问来源于stack exchange,提问作者user8813240
相关产品推荐
相关产品推荐

