执行期间未定义较大对象中的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的新手...

评论
  • quo_et
    quo_et 回复

    Store a pointer in to the class itself as a variable in the class and use it inside the inner function instead of this, because this inside the inner function refers to the function itself not the class:

    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);
    
       var self = this; // <------------------------ HERE
       this.draw = function() {
            self.ctx.lineTo(this.x, this.y);
            self.ctx.stroke();
        }
    
        this.updateRight = function() {
            self.x += this.speed;
            self.draw();
        }
    
        // Same functions as the above one, but for the other directions
    }