javascript - 较大对象中的 this.objectName 在执行期间变得未定义
问题描述
我用 HTML Canvas 创建了一个项目,它运行良好。一开始是这样的:
let canvas = document.querySelector('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
let ctx = canvas.getContext('2d');
function Line(x, y, context, length, speed) {
this.x = x;
this.y = y;
this.ctx = context;
this.length = length;
this.speed = speed;
this.isDrawingNow = false;
this.initialCoordinates = {
x: this.x,
y: this.y
}
console.log(this.initialCoordinates);
this.ctx.beginPath();
this.ctx.moveTo(this.x, this.y);
this.draw = function() {
this.ctx.lineTo(this.x, this.y);
this.ctx.stroke();
}
this.updateRight = function() {
this.x += this.speed;
this.draw();
}
// Same functions as the above one, but for the other directions
}
let line = new Line(50, 50, ctx, 30, 1);
function animateRight() {
if (line.initialCoordinates.x + line.length <= canvas.width) {
line.isDrawingNow = true;
if (line.x < line.initialCoordinates.x + line.length) {
requestAnimationFrame(animateRight);
line.updateRight();
} else {
line.initialCoordinates.x = line.x;
line.isDrawingNow = false;
}
}
}
// Same functions as the above one, but for left, up, down directions
window.addEventListener('keydown', keyDown); // Event listener for the arrow keys
function keyDown(e) {
if (e.key === 'ArrowLeft' && !line.isDrawingNow) {
animateLeft();
} else if (e.key === 'ArrowRight' && !line.isDrawingNow) {
animateRight();
// the other keys
}
}
然后我认为我必须在 Line 对象中包含 animateRight() (animateDirection 函数)。我这样做了:
// Same as the old object plus:
this.animateRight = function() {
console.log(this.initialCoordinates);
if (this.initialCoordinates.x + this.length <= canvas.width) {
this.isDrawingNow = true;
if (this.x < this.initialCoordinates.x + this.length) {
requestAnimationFrame(this.animateRight);
this.updateRight();
} else {
this.initialCoordinates.x = this.x;
this.isDrawingNow = false;
}
}
}
// The other directions...
// Now I have to call the animateDirection on arrowkey press like this (line is the new Line):
function keyDown(e) {
if (e.key === 'ArrowLeft' && !line.isDrawingNow) {
line.animateLeft();
} else if (e.key === 'ArrowRight' && !line.isDrawingNow) {
line.animateRight();
}
不幸的是,新代码不起作用,当我按右箭头时,我收到错误“this.initialCoordinates is undefined”。我使用firefox调试器来查找问题。我看到 animateRight 被调用了一次,requestAnimationFrame 再次调用 animateRight ,但是这次 this.initialCoordinates 是未定义的,对于 this.length 也是如此,所以程序停止了。我不明白有什么问题。请帮我!我是 OOP 的新手...
解决方案
在 JavaScript 中, 的值this
取决于函数的调用方式。如果函数像方法一样被调用,obj.func()
,this
将是obj
。如果函数被正常调用,func()
,this
将是undefined
(或非严格模式下的全局对象)。
您正在将一个函数 ( this.animateRight
) 传递给requestAnimationFrame
,它像普通函数一样调用它,因此在其中this
无法正常工作。
在过去的 JS 中,这通常通过分配this
给一个变量(通常称为self
)来解决。但是,现在有更好的方法来解决这个问题:
1.箭头功能
箭头函数是上述规则的一个例外this
。它们从定义它们的范围中获取值。
// [...]
if (this.x < this.initialCoordinates.x + this.length) {
requestAnimationFrame(() => {
this.animateRight();
});
this.updateRight();
} else {
// [...]
2.Function.prototype.bind()
函数的bind
方法返回一个新函数,它将调用具有指定值的函数this
。(在函数中绑定this
到指定值。)
// [...]
if (this.x < this.initialCoordinates.x + this.length) {
requestAnimationFrame(this.animateRight.bind(this));
this.updateRight();
} else {
// [...]
这种方法不如箭头函数灵活,因为你只能直接调用一个函数。
推荐阅读
- node.js - 已安装 npm 包 (PeerJS) 但在命令行中无法识别
- javascript - 如何添加在悬停时触发视频播放的覆盖 - 现在覆盖在悬停时阻止播放
- python - 运行 HTMLrequests() 时出现 Tracemalloc 错误
- python - 如何在 python 函数中使用气流 jinja 模板?
- java - Keycloak 服务器作为 Eureka 客户端
- kubernetes - Microk8s 入口 - defaultBackend
- uitableview - 如何在主线程内推送 DiffableDataSourceSnapshot 更新?
- javascript - 无法加载本地 JSON 文件
- python - 为 virtualenv 设置 PYTHONIOENCODING=utf-8
- prometheus - Victoria Metrics - 删除缺少标签的时间序列