我对JavaScript范围的方式有点新意,所以这是我的问题:
"use strict";
function Explorer(xPos, yPos) {
// Inheritance
GraphicsEntity.call(this, {
x: xPos,
y: yPos,
width: 32,
height: 32
});
// Local fields
var _texture = new Image();
// Contruct
_texture.addEventListener("load", function() {
this.graphics.drawImage(_texture, 0, 0);
}, false);
_texture.src = "explorer.png";
}
这将抛出异常:Uncaught TypeError:无法调用未定义的方法'drawImage'
我知道这是由于JavaScript范围的方式,因为'this'现在指的是'_texture'字段。 正如您所看到的,Explorer(某种类似于播放器的对象)继承自GraphicsObject,而GraphicsObject又具有属性图形(canvas元素的上下文)。
我找到了一种解决这个问题的方法,但在我看来这有点肮脏:
"use strict";
function Explorer(xPos, yPos) {
// Inheritance
GraphicsEntity.call(this, {
x: xPos,
y: yPos,
width: 32,
height: 32
});
// Local fields
var _texture = new Image();
var _graphics = this.graphics;
// Contruct
_texture.addEventListener("load", function() {
_graphics.drawImage(_texture, 0, 0);
}, false);
_texture.src = "explorer.png";
}
所有这些都按预期工作,图像被整齐地绘制到画布元素上。 唯一的问题是我现在有另外一个我不想要的'图形'的参考。
所以我的问题是: 有没有办法让'this'引用Explorer对象,或强制范围改变?
答案 0 :(得分:3)
this
始终是函数的本地函数,每次调用函数时都会对其进行求值,具体取决于函数的调用方式。在这种情况下,浏览器调用函数this
设置为_texture
指向的图像对象。
由于从外部范围查找正常变量,您只需将旧this
保存到某个变量:
function Explorer(xPos, yPos) {
var self = this;
// Inheritance
GraphicsEntity.call(this, {
x: xPos,
y: yPos,
width: 32,
height: 32
});
// Local fields
var _texture = new Image();
// Contruct
_texture.addEventListener("load", function () {
self.graphics.drawImage(_texture, 0, 0);
}, false);
_texture.src = "explorer.png";
}
答案 1 :(得分:2)
你没有展示函数GraphicsEntity
,但我很确定问题是这样的:
GraphicsEntity.call(this, {
在您的函数Explorer
中,this
将成为全局对象(除非Explorer
也使用call
调用),这就是对{{call
的调用1}}将this
设置为GraphicsEntity
。这可能是你得到这个例外的原因。
此外,GraphicsEntity
是对象还是功能?我问,因为call
期待功能。 call
调用给定的函数,将第一个参数设置为this
值,后续参数作为该函数的参数传递。
修改强>
正如Esailija所说,this
值在您的加载事件回调中与您在函数开头的回调不同。将this
的值保存到函数开头的局部变量中,并在回调中使用 。
答案 2 :(得分:1)
一种可能的解决方案是使用包装函数来创建您需要的上下文并捕获您的状态。
如:
function draw(me) {
me.graphics.drawImage(_texture, 0, 0);
}
function wrapper(me) {
return function () { draw(me) };
}
...
_texture.addEventListener('load', wrapper(this));
...
它比你的解决方案更简洁吗?这是有争议的,但你可以使它足够通用,它可以在其他环境中重复使用。
答案 3 :(得分:1)
您也可以使用bind将上下文绑定到函数作用域
"使用严格&#34 ;;
function Explorer(xPos,yPos){
// Inheritance
GraphicsEntity.call(this, {
x: xPos,
y: yPos,
width: 32,
height: 32
});
// Local fields
var _texture = new Image();
// Contruct
_texture.addEventListener("load", function() {
this.graphics.drawImage(_texture, 0, 0);
}.bind(this), false);
_texture.src = "explorer.png";
}