【问题标题】:Timeout with bind, call & apply methods绑定、调用和应用方法超时
【发布时间】:2015-06-19 21:38:48
【问题描述】:

到目前为止,在创建需要访问其父级的函数之前,我一直使用var self = this。然而,bind() 方法似乎是一种更合适的方法,我正在探索该选项以及apply()call() 方法。

这是我用来比较所有三个的:

jsFiddle

(function(){

    this.say = function(text){
        
        console.log(text);
    }
        
    this.run = function(){
        
        console.clear();
        
        setTimeout(function(){
            this.say('bind');
        }.bind(this), 1000);
        
        setTimeout(function(){
            this.say('call');
        }.call(this), 1000);
        
        setTimeout(function(){
            this.say('apply');
        }.apply(this), 1000);
    }
    
    this.run();
    
})();

但是脚本给我留下了一些问题:

  1. 为什么call()apply() 方法不像bind() 方法那样尊重超时,我应该使用哪一个?

  2. 以下行为相似的语法之间是否有任何区别:

    setTimeout( function(){ this.say('bind'); }.bind(this) , 1000);
    
    setTimeout( (function(){ this.say('bind'); }).bind(this) , 1000);
    
    setTimeout( (function(){ this.say('bind'); }.bind(this)) , 1000);
    

【问题讨论】:

  • .call.apply 的工作方式与 .bind 的工作方式不同。他们立即调用该函数。
  • 同意@JesseKernaghan。 callapply 调用函数,而 bind 只绑定上下文。

标签: javascript closures this settimeout iife


【解决方案1】:

您在这里遗漏了一个关键点(但关键点在文档中非常模糊)。

你知道每当你写这样的函数时:

function something() {
    // ... whatever
}

它只是一个单独的函数引用。它还没有被调用。

当你写这样的东西时:

(function something() {

})()

或者这个:

function something() { ... }

something();

您现在调用了该函数。这是两个完全不同的概念。

在第一个函数只是坐在那里而没有被调用的情况下,它被称为函数引用,这正是.bind 返回的内容:函数引用。

.call.apply 在新上下文中返回任何函数的返回值。所以在虚假的 JavaScript la-la 土地上,它看起来像这样:

function() {

}.bind(this)

// returns a function reference: function() {  }

鉴于:

function() {
    return 'hello';
}.call(this)
// returns hello... NOT A FUNCTION REFERENCE!

你看...

你可能永远不会做这样的事情:

function hello() {
    return true;
}

setTimeout(hello(), 100);

你会得到一个错误:setTimeout expected a Function, and it received a Boolean,或者类似的东西。

^ 这不是一个非常语义错误,但它仍然是一个错误。

但是,你做的是这样的:

function hello() {
    return true;
}

setTimeout(hello, 100);

看到区别了吗?最后一个例子没问题,因为你传入了一个函数引用

因为在内部,setTimeout 做了这样的事情:

window.setTimeout = function(callback) {
    // a bunch of other stuff, and...

    callback();
};

就您的第二个问题而言...

这些几乎都是等价的。闭包是有意义的,尽管当您声明不想让其他对象访问的变量时。

为了帮助您稍微了解闭包,让我们假设我们甚至没有在谈论 JavaScript。

在数学方面,您知道如何进行a + b * c 之类的操作吗?

嗯,当你用括号对它们进行分组时,它会改变行为:(a + b) * c

现在,显然这与 JavaScript 不太相关,因为在 JavaScript 中我们并不担心运算顺序(除非您实际上是在 JavaScript 中进行数学运算),但整个想法是这些括号只是充当一个容器(我们称之为闭包),用于存放其中的任何内容。

因此,当您将函数放在括号内时,您只是将该函数隐藏在外部世界之外,但它仍然可以返回内容,并且仍然可以访问父范围(例如 window)。

一个很酷的例子:

var name = (function(name) {
    return name
})(function() {
    return 'Jane';
}());

console.log(name); // => Jane

【讨论】:

    【解决方案2】:

    .call.apply 都会立即执行调用它们的函数。这意味着在这些情况下,您将匿名函数上callapply结果 传递给setTimeout,结果是undefined,因为这些函数不会返回任何事物。

    另一方面,bind 返回一个新函数,然后您将其正确传递给setTimeout。要获得调用并应用类似的行为,请将它们移动到匿名函数中:

        setTimeout(function(){
            this.say.call (this, 'call');
        }, 1000);
    

    例如。

    1. Afaik 那些是等价的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-10-21
      • 1970-01-01
      • 1970-01-01
      • 2013-09-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多