对象/函数/类声明周围的括号是啥意思? [复制]
Posted
技术标签:
【中文标题】对象/函数/类声明周围的括号是啥意思? [复制]【英文标题】:What do parentheses surrounding an object/function/class declaration mean? [duplicate]对象/函数/类声明周围的括号是什么意思? [复制] 【发布时间】:2010-10-01 05:49:37 【问题描述】:我是 javascript 和 YUI 的新手。在 YUI 库示例中,您可以找到此构造的许多用途:
(function()
var Dom = YAHOO.util.Dom,
Event = YAHOO.util.Event,
layout = null,
...
)();
我认为最后一对括号是在声明之后执行函数。
...但是前面那组围绕函数声明的括号呢?
我认为这是范围问题;那是将内部变量隐藏到外部函数和可能的全局对象中。是吗?更一般地说,这些括号的机制是什么?
【问题讨论】:
这也在Difference between (function())(); and function()();中讨论。 我认为我们需要按原样复制两个副本,因为它们的表述方式截然不同。 这是一个不删除的好理由,但我不明白为什么我们不能作为副本关闭。 在链接的问题之前没有问过这个问题... 【参考方案1】:关于该主题的一些注意事项:
括号:
浏览器(引擎/解析器)将关键字函数与
[optional name]([optional parameters])...code...
所以在像 function()() 这样的表达式中,最后一个括号没有意义。
现在想想
name=function() ; name() !?
是的,第一对括号强制匿名函数变成一个变量(存储表达式),第二个启动评估/执行,所以 ( function() )( ) 有道理。
实用程序:?
用于在加载时执行一些代码并将使用的变量与页面的其余部分隔离,尤其是在可能发生名称冲突时;
将 eval("string") 替换为
(新函数("string"))()
为“ =?: ”运算符包装长代码,例如:
结果 = exp_to_test ? (function()... long_code ...)() : (function()...)();
【讨论】:
对于 case function name()(),变量名称是隐式创建的,因此在代码定义之后放置大括号是 name() 的简写;【参考方案2】:如果您愿意,第一个括号用于操作顺序。围绕函数定义的一组括号的“结果”是函数本身,实际上,第二组括号执行。
至于它为什么有用,我还不足以成为一个 JavaScript 向导,我没有任何想法。 :P
【讨论】:
【参考方案3】:见this question。如果您使用函数名称,则第一组括号不是必需的,但无名函数需要此构造,并且括号用于编码人员在浏览代码时意识到他们正在查看自调用函数(参见一位博主的 @ 987654322@).
【讨论】:
如果您使用的是命名函数,则确实需要括号,但如果您将函数的结果分配给变量,则可以省略它们。即 function myResult () ...() 将失败,但 var myResult = function ... () 将工作 最佳实践链接中的精彩解释【参考方案4】:它是一个自动执行的匿名函数。第一组括号包含要执行的表达式,第二组括号执行这些表达式。
当试图从父命名空间隐藏变量时,这是一个有用的结构。函数内的所有代码都包含在函数的私有范围内,这意味着它根本无法从函数外部访问,使其真正成为私有的。
见:
http://en.wikipedia.org/wiki/Closure_%28computer_science%29
http://peter.michaux.ca/articles/javascript-namespacing
【讨论】:
括号仅在此上下文中是必需的,因为 JavaScript 中的function
可以是语句或表达式,具体取决于上下文。括号强制它成为一个表达式。以下内容也是有效的:var x = function () return 1 ()
,即使没有括号。只是一个函数表达式和该表达式的应用程序(...)
。在这种情况下,我建议在左括号前放置一个;
:我编写无分号的代码,并且以(
开头的行可能会被解析为从上一行继续的表达式。
@user166390 => 为什么要在“”之后加上“()”?
等等......所以这个烂摊子只是为了绕过 JS 使用的奇怪的作用域?
@Beska:不是这样。 JavaScript 是函数作用域(广义而言),这并不奇怪。并且可以在单个表达式中声明和执行函数。更公平地说,使用它来实现“私有”变量的“hack”更多是由于 JavaScript 中缺乏成熟的模块系统。【参考方案5】:
继续跟进安迪休谟和其他人所说的话:
围绕匿名函数的“()”是 ECMA 规范第 11.1.6 节中定义的“分组运算符”:http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf。
从文档中逐字记录:
11.1.6 分组运算符
产生式 PrimaryExpression : ( Expression ) 的评估如下:
-
返回计算表达式的结果。这可能是引用类型。
在这种情况下,函数被视为表达式。
【讨论】:
【参考方案6】:Andy Hume 差不多 gave 答案,我只是想补充一些细节。
使用此构造,您正在创建一个具有自己的评估环境或闭包的匿名函数,然后您立即对其进行评估。这样做的好处是您可以访问在匿名函数之前声明的变量,并且可以在此函数中使用局部变量,而不会意外覆盖现有变量。
var 关键字的使用非常重要,因为在 JavaScript 中,默认情况下每个变量都是全局变量,但是使用该关键字可以创建一个新的 词法作用域 变量,也就是说,它在两个大括号之间之间的代码可见。在您的示例中,您实际上是在为 YUI 库中的对象创建短别名,但它具有更强大的用途。
我不想给你留下一个代码示例,所以我在这里放一个简单的例子来说明一个闭包:
var add_gen = function(n)
return function(x)
return n + x;
;
;
var add2 = add_gen(2);
add2(3); // result is 5
这里发生了什么?在函数 add_gen 中,您正在创建另一个函数,它将简单地将数字 n 添加到其参数中。诀窍是在函数参数列表中定义的变量充当词法范围的变量,就像用 var 定义的变量一样。
返回的函数定义在 add_gen 函数的大括号之间,因此即使在 add_gen 函数之后它也可以访问 n 的值已经执行完毕,这就是为什么在执行示例的最后一行时会得到 5。
借助词法范围的函数参数,您可以解决因在匿名函数中使用循环变量而引起的“问题”。举个简单的例子:
for(var i=0; i<5; i++)
setTimeout(function()alert(i), 10);
“预期”结果可能是从零到四的数字,但您会得到四个五的实例。发生这种情况是因为 setTimeout 和 for 循环中的匿名函数使用 very same i 变量,所以当函数被评估时,i 将是 5。
您可以通过使用问题中的技术以及函数参数是词法范围这一事实来获得天真的预期结果。 (我在other answer 中使用过这种方法)
for(var i=0; i<5; i++)
setTimeout(
(function(j)
return function()alert(j);
)(i), 10);
通过立即评估外部函数,您将在每次迭代中创建一个名为 j 的完全独立变量,i 的当前值将被复制 到这个变量中,所以你会得到第一次尝试时天真预期的结果。
我建议您尝试了解http://ejohn.org/apps/learn/ 的优秀教程,以更好地了解闭包,这是我学到的非常非常多的地方。
【讨论】:
+1 确实很棒的答案。【参考方案7】:...但是围绕所有函数声明的前一轮 parenteses 呢?
具体来说,它使 JavaScript 将 'function() ...' 构造解释为内联匿名函数表达式。如果省略括号:
function()
alert('hello');
();
你会得到一个语法错误,因为 JS 解析器会看到 'function' 关键字并假设你正在启动一个函数 statement 的形式:
function doSomething()
...而且你不能有一个没有函数名的函数语句。
函数表达式和函数语句是两种不同的结构,它们的处理方式非常不同。不幸的是,语法几乎相同,所以它不仅让程序员感到困惑,甚至解析器也很难分辨出你的意思!
【讨论】:
以上是关于对象/函数/类声明周围的括号是啥意思? [复制]的主要内容,如果未能解决你的问题,请参考以下文章