用'this`混淆回调

时间:2016-11-21 14:21:29

标签: javascript jquery

我有这个时钟对象:

var Clock = {
    start: function () {
      $('#btnScrollPause').show();
      $('#btnScrollResume').hide();

      advance();
      this.interval = setInterval(function () {
        advance();
      }, 5000);
    },

    pause: function () {
      $('#btnScrollPause').hide();
      $('#btnScrollResume').show();
      this.reset();
    },

    resume: function () {
      if (!this.interval) {
        this.start();
      }
    },

    reset: function () {
      clearInterval(this.interval);
      delete this.interval;
    }
  };

我有两个按钮可以暂停和恢复元素的自动滚动,但我的困惑在于我已经附加到它们的点击处理程序。

如果我像这样调用暂停功能:

// 1
$('#btnScrollPause').click(function () {
  Clock.pause();
});

它可以正常工作,但是如果我尝试减少这样的代码:

// 2
$('#btnScrollPause').click(Clock.pause);

它不再有效,我收到错误" this.reset未定义"。另外,如果我创建一个函数并在click处理程序中使用它:

// 3
$('#btnScrollPause').click(scrollPause);

function scrollPause() {
  Clock.pause();
}

有效!有人可以解释为什么1和3有效,但有2个没有?

2 个答案:

答案 0 :(得分:4)

这与this关键字在JavaScript中的工作方式有关。将方法作为回调传递给另一个函数时,该方法与对象分离,this关键字不引用对象。另外,jQuery事件方法修改回调的this值以引用事件的所有者,即DOM元素。

您拥有的一个选项是使用.bind功能:

$('#btnScrollPause').click(Clock.pause.bind(Clock));

相关问题:How does the “this” keyword work?

答案 1 :(得分:2)

this对象绑定在JavaScript中是易失性的...也就是说,它并不总是指向同一个对象,并且它的绑定可以从一行代码更改为下一行代码。如何调用包含单词this的代码确定它将绑定到哪个对象。

您是否创建了Clock的实例(即var c = new Clock())然后说:

$('#btnScrollPause').click(c.pause);

它会起作用,因为this将绑定到Clock变量引用的c的实例。

但是当它代表你的代码时,this被绑定到你的按钮,因为这是启动代码的对象。

以下是一份清单,您可以通过该清单了解this将绑定到哪个...

如果调用包含this的代码:

  1. 作为对象实例的方法或属性(通过实例变量):

    var o = new Object(); 
    
    // "this" will be bound to the "o" object instance
    // while "someProperty" and "someMethod" code executes
    o.someProperty = someValue;
    o.someMethod();
    
  2. 通过.call().apply().bind()Array.prototype.fn调用:

    // "this" will be bound to the object suppled as the "thisObjectBinding"
    someFunction.call(thisObjectBinding, arg, arg);
    someFunction.apply(thisObjectBinding, [arg, arg]);
    var newFunc = someFunction.bind(thisObjectBinding, arg, arg);
    

    此外,一些Array.prototype方法允许传递thisObject,这将在方法调用的持续时间内改变绑定:

    Array.prototype.every( callbackfn [ , thisArg ] )
    Array.prototype.some( callbackfn [ , thisArg ] )
    Array.prototype.forEach( callbackfn [ , thisArg ] )
    Array.prototype.map( callbackfn [ , thisArg ] )
    Array.prototype.filter( callbackfn [ , thisArg ] )
    
  3. 如果没有其他方案适用,则会发生默认绑定。

    3A。 "use strict"生效后thisundefined

    3B。没有"use strict"生效:this绑定到全局对象

  4. **注意:使用this也可能会影响eval()绑定,但作为一般的最佳做法,应避免使用eval()