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是基于方法执行的上下文。