为什么闭包对JavaScript很重要?


16

C#的lambda表达式也有闭包,但C#社区或书籍很少讨论。与C#世界相比,我看到更多的JavaScript人和书籍谈论其闭包。这是为什么?


3
因为JavaScript被视为一流的功能语言,而C#是经典的OOP语言。不同的范例,不同的编程风格。
雷诺斯2011年

1
具有一流的功能确实使该语言成为一种功能语言。PHP(从5.3开始),python或D具有一流的功能。您会说它们是功能语言吗?当然不是,而javascript也是如此。
deadalnix11年

1
@deadalnix JavaScript是一种多范式语言。它主要支持过程,功能和原型OO范式。它绝不是一种纯粹的功能语言,但是您可以轻松地在功能范式中编写javascript,而无需改变语言。我会说C#和python相同。
雷诺斯2011年

3
@deadalnix是允许您定义Y组合器的语言,是一种功能性语言。根据定义。
SK-logic

1
@deadalnix:我想归结为这个语言提倡什么方法的问题。有很多JavaScript框架和平台(尤其是node.js和DOM(事件模型))都严重依赖于一阶函数。PHP确实具有允许完全相同的编程样式的功能,但是如果您看一下标准API或许多框架,那么您会发现它并不是语言的真正核心。
back2dos

Answers:


5

因为javascript不具有名称空间之类的功能,所以您可以很容易地将各种全局对象弄乱。

因此,重要的是能够在其自己的执行环境中隔离一些代码。封闭是完美的。

在像C#这样的语言中,闭包的使用是没有意义的,在C#中,您具有名称空间,类等来隔离代码,而不是将所有内容置于全局范围内。

javascript代码的一种非常常见的做法是这样写:

(function(){
    // Some code
})();

如您所见,这是一个匿名函数声明,其后立即执行。因此,无法从外部访问函数中定义的所有内容,并且不会弄乱全局范围。只要某些代码可以使用该函数的执行上下文(例如在此上下文中定义的嵌套函数),就可以将其作为回调或任何其他形式传递。

JavaScript与C#是一种非常不同的语言。它不是面向对象的,而是面向原型的。这最终导致非常不同的实践。

无论如何,闭包是好的,所以即使在C#中也要使用它们!

编辑:在对stackoverflow的聊天进行了一些讨论之后,我认为必须解决这一难题。

示例代码中的函数不是闭包。但是,此功能可以定义局部变量和嵌套函数。使用这些局部变量的所有嵌套函数都是闭包。

这对于在不影响全局范围的情况下跨一组功能共享某些数据很有用。这是javascript中闭包的最常见用法。

闭包比共享这样的数据要强大得多,但是让我们现实一点吧,大多数程序员对函数式编程一无所知。在C#中,您将使用类或名称空间进行此类使用,但是JS不提供此功能。

使用闭包可以做更多的事情,而不仅仅是保护全局范围,但这就是您在JS源代码中看到的。


9
那不是关闭。您描述了使用函数创建本地范围的优势。
Raynos 2011年

2
如果关闭了自由变量,则关闭仅是关闭。也感谢您告诉我,我不知道JavaScript的工作原理:)
Raynos 2011年

2
而是通过叫我一个初学者随意在JavaScript SO聊天室提出实际的论点来破坏我。这个讨论实际上并不属于这里,但是我将在SO聊天中愉快地讨论您的误解。
雷诺斯2011年

1
不赞成投票。JavaScript是大量面向对象的。它不是基于类的,但是这样的功能很容易编写。它具有一流的功能,利用闭包使其很适合事件驱动的范例,据作者Brendan Eich称,它的主要灵感来源是Scheme。我不太确定您认为函数式语言是什么,但是有趣的是,您似乎认为基于类的继承在某种程度上很关键,而不再需要在可以传递函数并将其应用于新的上下文中时完全不再需要。
埃里克·雷彭

2
-1也是如此。这没有描述闭包,而是描述了作用域。
2013年

12

可能是因为JavaScript面向对象的流行实现依赖于闭包。让我们看一个简单的例子:

function counter() {
   var value = 0;
   this.getValue = function() { return value; }
   this.increase = function() { value++; }
}

var myCounter = new counter();
console.log(myCounter.getValue());
myCounter.increase();
console.log(myCounter.getValue());

方法getValueincrease实际上是闭包,封装了变量value


3
-1“取决于闭包”这是非常主观的。它不是。
雷诺斯2011年

Raynos:希望向我们展示如何创建和使用不带闭包的私人成员?
user281377 2011年

1
@ammoQ在JavaScript中没有私有的东西。您的意思是“因为JavaScript经典的OO仿真取决于闭包”。JavaScript OO是原型,这是一个不同的范例。不过,这是一个很好的答案,“我们在JavaScript中使用闭包是因为需要模仿经典的OO”
Raynos 2011年

1
@keppla我的意思是“ OO取决于闭包”是主观的。您根本不需要OO的关闭。
雷诺斯2011年

2
您将我暴露为我的代表妓女…
user281377 2011年

4

因为许多使JavaScript“可承受”的库都在使用它们。

看一下JQueryPrototypeMooTools,仅举三个流行的例子。这些库中的每一个都each为它们的集合提供一种方法,作为迭代的首选方法,该方法使用迭代器函数。当访问外部范围中的值时,该函数将是一个闭包:

[1,2,3].each(function(item) {
   console.log(item);
});

而且它还不止于此:Ajax中的回调,Ext.js中的事件处理等都具有函数,并且如果您不想使用仅被调用一次的100ed函数膨胀代码,那么闭包是可行的方法。


1
为什么不关闭?console.log在外部范围中定义,因此console“自由变量”也是。而且,为什么实际上是一个for循环(没有什么不同)是不好的做法?
keppla 2011年

@Raynos:我对闭包的定义是“包含一个自由变量的块”,它不会丢失该状态,它的自由变量恰好在顶级范围内。但是,为了支持我的观点,请考虑使用以下方法:pastie.org/2144689。为什么这不好?
keppla 2011年

我仍然认为“关闭”全局数据被认为是作弊行为。我同意在范围链上访问数据很好,这是减少访问的简单好习惯。
雷诺斯2011年

同意最小化访问权限
keppla 2011年

应该注意的是,使用数组迭代器(forEach,map,reduce等),它们成为闭包的理由为零,它们具有直接传递给它们的所有状态。我认为将它们作为关闭是一种反模式
Raynos 2012年

3

我同意其他答案,即使用JavaScript进行“良好”编码在很大程度上取决于闭包。但是,除此之外,这可能只是该功能在每种语言中使用了多长时间的问题。自最早的实现以来,JavaScript基本上已经关闭了。另一方面,C#仅在Visual Studio 2008附带的3.0之后才具有它们。

我遇到的许多C#程序员仍在从事2.0项目。即使他们在3.0或4.0中工作,他们仍然经常使用2.0习语。我喜欢闭包;希望随着该概念在C#开发人员之间的传播,它们将在C#中得到更广泛的使用。


2

主要原因是因为C#是静态类型的,并且函数只能访问单个预定的环境,这阻碍了闭包的用处。

另一方面,在JavaScript中,闭包使函数在作为对象属性被访问并成为一类对象时可以充当方法,也可以将它们注入不同的环境中,从而允许子例程在不同的上下文中运行。


1
静态类型输入与此有何关系?闭合是正交的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.