关于this和call的指向问题

问题一:我在一个构造函数里写了setTime()方法和moveSnake方法,在setTime()里面用setInterval调用moveSnake方法,此时为什么this指向的是window?
问题二: 我在setTime()里面用setInterval(this.moveSnake.call(Snake),500);为什么返回的是图片描述而不是图片描述,我依然不能console.log(this.snakeArr)。
但是换了这种

(function(theThis){
    var that = theThis;
    that.timer = setTimeout(function() {
        that.moveSnake();            
    }, 500);
})(this);

就能让this指到Snake这个构造函数呢?
那为什么我直接把this当成参数传给setTimeout不行呢:

var timeTest = setTimeout(function(this) {
                this.moveSnake();    
            },500);

这个样子就是Unexpected token this了
以下是这一部分的代码,其他不相关的没有贴出:

function Snake(id, score, speed, x, y){
    
    this.id = document.getElementById(id);
    this.ctx = this.id.getContext("2d");
    this.cellWidth = 10;    //每个格子的大小
    this.score = document.getElementById(score);
    this.speed = document.getElementById(speed);
    this.x = x;
    this.y = y;
    // 画canvas大小 
    this.id.width = this.x * this.cellWidth;
    console.log(this.id.width);
    this.id.height = this.y * this.cellWidth;
    this.id.style.border = "1px solid black";
    this.setDirection();
}

Snake.prototype = {
    init: function() {
        this.snakeArr = [[1,parseInt(this.y/2)],[2,parseInt(this.y/2)]];    //蛇身长度。初始化时只有两个长度,每一个点存了[x,y]两个坐标,parseInt(this.y/2)是整个canvas的中间取整,length/push的是蛇头,unshift的是蛇尾
        this.foodPosition = []; //储存当前食物的位置,这里每次都初始化为0
        this.direction = 1; //方向:右1,下2,左3,上4
        //画画布
        this.ctx.fillStyle ="#fff";
        this.ctx.fillRect(0,0,this.cellWidth*this.x,this.cellWidth*this.y);
    
        this.drawSnake();   //记得写this
        this.drawFood();
        this.setTime();
    },
    //蛇的移动
    moveSnake: function(){
        console.log(this);  //window
        console.log(this.snakeArr);
    },
    //定时器
    setTime: function() {
        // setTimeout(this.moveSnake.call(Snake),500);  //为什么这样指过去不行?

        (function(theThis){
            var that = theThis;
            that.timer = setTimeout(function() {
                that.moveSnake();            
            }, 500);
        })(this);
    },
    
}

阅读 1.8k
2 个回答

老生常谈

1.函数内部的this指向依赖于函数被调用的方式setInterval中的回调函数是在全局环境下调用的,因此this指向window

2.Function.ptototype.call绑定的是函数运行时的this,这里你将this绑定到了Snake上,但是Snake是构造函数而非实例,因此打印结果是Snake构造函数

3.你把this当参数传进IIFE,并赋给了另外一个变量,因此这个变量就是this

4.之所以直接传this不行,是因为setTimeout的回调函数本来就不会传入参数,因此你的形参this的值是undefined

解决方案有二
1.声明一个变量保存this,回调函数中直接调用这个变量的方法
2.使用箭头函数,自动绑定当前作用域的this

this是关键字,不能作为形参的

var timeTest = setTimeout(function(this) {
                this.moveSnake();    
            },500);

所以会报Uncaught SyntaxError: Unexpected token this

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题