javascript 构造函数 属性 在调用事件后变为未定义
javascript constructor property becomes undefined after event is called
var Context = {
canvas: null,
context: null,
create: function(canvas_tag_id, size){
this.canvas = document.getElementById(canvas_tag_id);
this.canvas.width = size[0];
this.canvas.height = size[1];
this.context = this.canvas.getContext('2d');
return this.context;
},
fps:1/30
};
$(function(){
// Initialize
Context.create('canvas', [798, 652]);
var s_size = [Context.canvas.width, Context.canvas.height]; // screen size
function Player(){
this.rect = [0, s_size[1]-40, 20, 40];
this.color = 'blue';
this.create = function(){
// function for creating player object
Context.context.beginPath();
Context.context.fillStyle = this.color;
Context.context.rect(
this.rect[0], this.rect[1], this.rect[2], this.rect[3]);
Context.context.fill();
};
this.control = function(){
// player movement control function
if (event.which == 39 || event.keyCode == 39){
alert(this.rect);
}
};
this.update = function(){
this.rect[0] += 1;
}
}
// player instance creation
var archie = new Player();
// game loop functions
function events(){
// Keydown events
function keydown(){
window.addEventListener('keydown', archie.control);
}
keydown();
}
function update(){
archie.update();
}
function render(){
Context.context.clearRect(0, 0, canvas.width, canvas.height);
archie.create();
}
function game(){
events();
update();
render();
}
setInterval(game, Context.fps);
});
如您所见,问题不在于代码的组织,而在于事件处理程序,因为播放器 class 的更新方法工作得很好,即使它是在事件处理程序之后创建的。
这里的问题到底是什么,我该如何解决?
在事件处理程序中,this
始终是事件处理程序绑定到的元素,而不是传入函数的构造函数。
要使代码更短,您正在做
var Player = function() {
this.rect = "something";
this.control = function(){
if (event.which == 39 || event.keyCode == 39){
alert(this.rect); // NOPE ... this is the element
}
};
}
var archie = new Player(); // create instance
window.addEventListener('keydown', archie.control); // some function in the instance
如果您只需要将对象作为 this
值,请使用 bind
window.addEventListener('keydown', archie.control.bind(archie));
另请注意,您的事件处理程序回调缺少 event
参数,并且依赖于全局 event
,并非所有浏览器 (Firefox) 都支持它,因此您应该这样做
this.control = function(event) {...
我经常使用的另一个解决方案是将 this
值存储在另一个变量 ex 中。 self
并在每个地方使用该副本,因此它可以是:
var Player = function() {
var self = this;
self.rect = "something";
self.control = function(event){
if (event.which == 39 || event.keyCode == 39){
alert(self.rect);
}
};
}
这保证您可以使用您想要的东西,因为this
是基于方法执行的上下文。
var Context = {
canvas: null,
context: null,
create: function(canvas_tag_id, size){
this.canvas = document.getElementById(canvas_tag_id);
this.canvas.width = size[0];
this.canvas.height = size[1];
this.context = this.canvas.getContext('2d');
return this.context;
},
fps:1/30
};
$(function(){
// Initialize
Context.create('canvas', [798, 652]);
var s_size = [Context.canvas.width, Context.canvas.height]; // screen size
function Player(){
this.rect = [0, s_size[1]-40, 20, 40];
this.color = 'blue';
this.create = function(){
// function for creating player object
Context.context.beginPath();
Context.context.fillStyle = this.color;
Context.context.rect(
this.rect[0], this.rect[1], this.rect[2], this.rect[3]);
Context.context.fill();
};
this.control = function(){
// player movement control function
if (event.which == 39 || event.keyCode == 39){
alert(this.rect);
}
};
this.update = function(){
this.rect[0] += 1;
}
}
// player instance creation
var archie = new Player();
// game loop functions
function events(){
// Keydown events
function keydown(){
window.addEventListener('keydown', archie.control);
}
keydown();
}
function update(){
archie.update();
}
function render(){
Context.context.clearRect(0, 0, canvas.width, canvas.height);
archie.create();
}
function game(){
events();
update();
render();
}
setInterval(game, Context.fps);
});
如您所见,问题不在于代码的组织,而在于事件处理程序,因为播放器 class 的更新方法工作得很好,即使它是在事件处理程序之后创建的。 这里的问题到底是什么,我该如何解决?
在事件处理程序中,this
始终是事件处理程序绑定到的元素,而不是传入函数的构造函数。
要使代码更短,您正在做
var Player = function() {
this.rect = "something";
this.control = function(){
if (event.which == 39 || event.keyCode == 39){
alert(this.rect); // NOPE ... this is the element
}
};
}
var archie = new Player(); // create instance
window.addEventListener('keydown', archie.control); // some function in the instance
如果您只需要将对象作为 this
值,请使用 bind
window.addEventListener('keydown', archie.control.bind(archie));
另请注意,您的事件处理程序回调缺少 event
参数,并且依赖于全局 event
,并非所有浏览器 (Firefox) 都支持它,因此您应该这样做
this.control = function(event) {...
我经常使用的另一个解决方案是将 this
值存储在另一个变量 ex 中。 self
并在每个地方使用该副本,因此它可以是:
var Player = function() {
var self = this;
self.rect = "something";
self.control = function(event){
if (event.which == 39 || event.keyCode == 39){
alert(self.rect);
}
};
}
这保证您可以使用您想要的东西,因为this
是基于方法执行的上下文。