【问题标题】:scopes in javascriptjavascript中的作用域
【发布时间】:2012-10-04 16:17:13
【问题描述】:

我在 javascript 中有一个 simpe 对象,它的方法很少。我想用 window.setTimeout 函数定期调用其中两个。我当前的代码如下所示。

var shakeResolver = function () {
 var resolveTimeout;
 console.log(this);
 var context = this;
 this.startShakeResolve = function () {
     this.resolveTimeout = window.setTimeout(this.call(context.stopShakeResolve, context), 2000);
     $(window)
         .on('devicemotion', this.onDeviceMotion);
 };

 this.onDeviceMotion = function (event) {};

 this.stopShakeResolve = function (context) {
     this.resolveTimeout = window.setTimeout(context.startShakeResolve, settings.interval);

 };

}

问题显然在于我误解了范围是如何工作的,看起来当从超时调用函数时,它是从另一个实际上不存在的上下文中调用的?

【问题讨论】:

  • 在第一次调用setTimeout 时,您会立即执行一个函数,并将其返回值(恰好未定义)作为要调用的函数传递超时。 (编辑:当然,假设您使用 this.call 调用通常的 Function.call 而不是您自己的变体。)
  • 什么是this?它是一个函数吗?你怎么打电话给shakeResolver?要了解有关this 的更多信息,请查看developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/…

标签: javascript scopes


【解决方案1】:

修改代码:setTimeout 的范围始终为window 对象。您可以使用 call applybind 更改函数上下文(旧 IE 浏览器 IE

var shakeResolver = function() {
    this.resolveTimeout;
    console.log(this);
    var context = this;
    this.startShakeResolve = function() {
        this.resolveTimeout = window.setTimeout(function() {
            context.stopShakeResolve.apply(context, arguments);
        }, 2000);

        $(window).on('devicemotion', function(){
                    context.onDeviceMotion.apply(context, arguments);
            });
    };

    this.onDeviceMotion = function(event) {
    };

    this.stopShakeResolve = function(context) {
        this.resolveTimeout = window.setTimeout(function() {
            context.startShakeResolve.apply(context, arguments)
        }, settings.interval);

    };
}

【讨论】:

    【解决方案2】:

    call() 将调用函数的上下文作为第一个参数。这意味着您的this.call(context.stopShakeResolve, context) 使您的上下文为context.stopShakeResolve,这意味着当调用函数时this 等效于context.stopShakeResolve

    只是为了更清楚:

    this.stopShakeResolve = function (context) {
        this.resolveTimeout = window.setTimeout(context.startShakeResolve, settings.interval);
    };
    

    它里面没有一个叫做shakeResolver的函数,所以它会抛出一个异常,告诉你它没有以这种方式调用的属性或方法。将调用更改为以下内容:

    this.stopShareResolve.call(this, context)
    

    【讨论】:

      猜你喜欢
      • 2013-01-14
      • 2010-12-01
      • 2015-08-22
      • 2018-06-25
      • 2011-10-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-01
      相关资源
      最近更新 更多