JavaScript中Ant类move方法内this指向错误无法调用inView方法如何解决?
问题根因
你遇到的this指向丢失问题,本质是move方法调用时没有绑定到Ant实例上导致的:如果move被作为回调函数传入定时器、事件监听等逻辑中执行,函数内的this会默认指向全局对象(严格模式下为undefined),和move函数本身没有关系。
修复现有代码的方案
方案1:构造函数内缓存实例指向(ES5兼容最优解)
在构造函数最顶部缓存this的指向,后续所有访问实例的地方都用缓存变量替代,不需要修改外部调用逻辑:
function Ant(x, y) { const self = this; // 顶部缓存Ant实例指向 this.x = x; this.y = y; this.val = 2; this.direction = dirs[Math.floor(Math.random() * dirs.length)]; this.carryingFood = false; this.inView = function () { fill("#008800"); switch (self.direction.toString()) { // 用self访问实例属性 case "0,1": return [ atXY(self.x - 1, self.y + 1), atXY(self.x, self.y + 1), atXY(self.x + 1, self.y + 1), ]; // 剩余switch分支同理全部替换为self } }; this.move = function() { var possibleMoves = self.inView(); // 用self调用实例方法 if (!self.carryingFood) { for (let move of possibleMoves) { if (move.val == 3) { self.x = move.x; self.y = move.y; self.carryingFood = true; move.eat(); } } } } this.draw = function () { fill("#FF0000"); rect(self.x * cellSize, self.y * cellSize, cellSize, cellSize); }; }
方案2:调用时绑定this
如果不想修改类内代码,在外部调用move方法时绑定实例即可,比如作为回调传入时写法为:
// 假设ant是已创建的Ant实例 setTimeout(ant.move.bind(ant), 16) // 绑定实例后再作为回调传入
方案3:用箭头函数定义方法
ES6箭头函数不会绑定独立的this,会继承外层作用域的this指向,直接修改方法定义即可:
this.move = () => { var possibleMoves = this.inView(); // 此处this自动指向Ant实例 // 剩余move逻辑不变 }
更合理的实现优化思路
你当前的写法会给每个Ant实例都单独创建inView、move、draw方法,会造成不必要的内存占用,推荐优化为以下实现:
- 改用ES6 Class语法,方法挂载到原型上,所有实例共享方法,大幅降低内存开销:
class Ant { constructor(x, y) { this.x = x; this.y = y; this.val = 2; this.direction = dirs[Math.floor(Math.random() * dirs.length)]; this.carryingFood = false; } inView() { fill("#008800"); switch (this.direction.toString()) { // 原有inView逻辑不变 } } move() { const possibleMoves = this.inView(); // 原有move逻辑不变 } draw() { fill("#FF0000"); rect(this.x * cellSize, this.y * cellSize, cellSize, cellSize); } }
- 优化
inView的冗余switch逻辑,提前建立方向和视野偏移的映射表,代码更简洁易维护:
// 提前定义全局方向映射表 const directionViewMap = { "0,1": [[-1,1], [0,1], [1,1]], "1,1": [[0,1], [1,1], [1,0]], "1,0": [[1,1], [1,0], [1,-1]], "1,-1": [[1,0], [1,-1], [0,-1]], "0,-1": [[1,-1], [0,-1], [-1,-1]], "-1,-1": [[0,-1], [-1,-1], [-1,0]], "-1,0": [[-1,-1], [-1,0], [-1,1]], "-1,1": [[-1,0], [-1,1], [0,1]] } // inView方法简化为查表逻辑 inView() { fill("#008800"); const offsets = directionViewMap[this.direction.toString()]; return offsets.map(([offsetX, offsetY]) => atXY(this.x + offsetX, this.y + offsetY)); }
内容的提问来源于stack exchange,提问作者Dion
相关产品推荐
相关产品推荐

