这些闭包的例子有什么不同

What is the difference in these examples of closures?

本文关键字:什么 闭包      更新时间:2023-09-26

我在每个测试用例中都有两种情况。我想了解其中的区别,并想更多地了解闭包。

测试1:

somefunction(someobj);

somefunction(function(){ return someobj; });

测试2

for(;;){
  someoperations;
}

for(;;)(function(iterator){
  someoperations;
})(iterator);

测试3:

var x = (function() {
  return {};
})();

(function() {
  //this = window
  var x = function() {
    //this = instance of x
    this.something = somethingelse;
  }
  //making it global OR making it available outside closure.
  return (this.x=x);
})();

我需要解释在每个测试用例中以第二种方式使用它的优点。

在javascript中,创建新变量作用域的唯一方法是在函数中。

是否需要新的范围将完全取决于情况。因此,您提供的一般示例不允许给出明确的答案。


为了给出更具体的内容,我们可以使用测试2,并应用这个非常常见的场景,其中someoperations是一个异步调用,类似于setTimeout:

for( var i=1; i<4; i++ ) setTimeout( function() { alert( i ); }, 1000 * i);

问题是,在循环中创建的每个函数(并传递给setTimeout)都引用了相同的i变量,而且因为它是一个setTimeout,它是非阻塞的,所以在调用在循环中生成的任何函数之前,循环都会完整结束。

结果是,每个函数都会提醒4,因为循环后i的值就留在了那里。

示例:http://jsfiddle.net/Ng3rr/


另一方面,如果在设置setTimeout的循环中调用一个函数,并将i的值传递给该函数,则发送给setTimeout的每个函数所引用的变量将是本地inner_i,它引用了传递给外部调用的值。

(我称之为inner_i以区分两者,但您也可以将内部变量命名为i。这样做被称为变量阴影。)

for( var i=1; i<4; i++ )(function( inner_i ){
  setTimeout( function() { alert( inner_i ); }, 500 * inner_i);
})( i );

现在,每个警报都显示在每次迭代期间收到的值。

正如你所看到的,这完全取决于情况。

示例:http://jsfiddle.net/Ng3rr/1/


为了与上面的例子形成对比,如果我们没有在循环中运行任何异步代码,那么外部函数就没有必要了。

此:

for( var i=1; i<4; i++ ) alert( i );

示例:http://jsfiddle.net/Ng3rr/2/

这个:

for( var i=1; i<4; i++ )(function( inner_i ){
    alert( inner_i );
})( i );

示例:http://jsfiddle.net/Ng3rr/3/

将具有相同的行为,使得外部功能不必要。


因此,调用外部函数会创建一个新的变量范围。在这个新的作用域中,变量将由在该作用域中创建的任何其他嵌套函数保留。

此外,虽然在该作用域中创建的变量可以在嵌套于该作用域的函数中访问,但它们在该作用域之外是不可用的。这样可以避免使用其他变量名污染周围的作用域。

让答案不受JavaScript限制。

有几种方法可以将函数用作变量/参数,其中一种方法嵌套在另一个函数中,称为"闭包"。

你可以在这里查看"闭包"的完整描述:

http://en.wikipedia.org/wiki/Closure_%28computer_science%29

我建议对于非常长的扩展代码使用单独的函数(情况1),对于短代码使用嵌套函数(情况2)。