围绕对象/函数/类声明的括号是什么意思?
我是JavaScript和YUI的新手。 在YUI库的例子中,你可以发现这个结构的许多用途:
(function() { var Dom = YAHOO.util.Dom, Event = YAHOO.util.Event, layout = null, ... })();
我想最后一对括号是在声明之后执行函数。
…但是围绕函数声明的前面一组括号呢?
我认为这是一个范围问题,就是隐藏内部variables的外部函数和可能的全局对象。 是吗? 更一般地说,括号里的机制是什么?
这是一个自我执行的匿名函数。 第一组括号包含要执行的expression式,第二组括号执行这些expression式。
当试图隐藏来自父命名空间的variables时,这是一个有用的构造。 函数中的所有代码都包含在函数的私有范围内,这意味着函数的外部根本无法访问,从而使其成为私有的。
看到:
安迪·休姆几乎给了答案,我只是想补充一些细节。
通过这个构造,你可以创build一个匿名的函数,并有自己的评估环境或者closures,然后你立即评估它。 关于这一点的好处是你可以访问在匿名函数之前声明的variables,并且你可以在这个函数中使用局部variables,而不会意外覆盖现有的variables。
var关键字的使用非常重要,因为在JavaScript中,每个variables默认都是全局variables,但是使用关键字创build一个新的, 词法变化范围的variables,也就是说, 两个大括号之间的代码可以看到这个variables。 在你的例子中,你基本上是为YUI库中的对象创build简短的别名,但是它有更强大的用途。
我不想离开你没有代码的例子,所以我会在这里举一个简单的例子来说明一个闭包:
var add_gen = function(n) { return function(x) { return n + x; }; }; var add2 = add_gen(2); add2(3); // result is 5
这里发生了什么? 在函数add_gen中,您正在创build另一个函数,它将简单地将数字n添加到其参数中。 诀窍是在函数参数列表中定义的variables充当词汇范围variables,就像用var定义的variables一样。
返回的函数在add_gen函数的大括号之间定义,所以即使在add_gen函数执行完成之后,它也可以访问n的值,这就是为什么在执行示例的最后一行时会得到5的原因。
借助函数参数的词法范围,可以解决在匿名函数中使用循环variables所带来的“问题”。 举一个简单的例子:
for(var i=0; i<5; i++) { setTimeout(function(){alert(i)}, 10); }
“预期”的结果可能是从零到四的数字,但是你可以得到四个五的实例。 发生这种情况是因为setTimeout和for循环中的匿名函数使用了非常相同的 ivariables,所以在函数得到评估的时候, 我将是5。
你可以通过在你的问题中使用这个技术来获得天真的结果,事实上,这个函数参数在词汇上是有范围的。 (我在其他答案中使用了这种方法)
for(var i=0; i<5; i++) { setTimeout( (function(j) { return function(){alert(j)}; })(i), 10); }
通过对外部函数的即时评估,您将在每次迭代中创build一个名为j的完全独立的variables,并将i的当前值复制到此variables中,以便您能够从第一次尝试中获得天真的结果。
我build议您尝试了解http://ejohn.org/apps/learn/上的优秀教程,以更好地理解closures,这是我非常了解的地方。;
…但是围绕所有function宣言的以前的巡回演唱会呢?
具体来说,它使JavaScript将“function(){…}”结构解释为内联匿名函数expression式。 如果您省略括号:
function() { alert('hello'); }();
你会得到一个语法错误,因为JSparsing器会看到'function'关键字,并假设你正在启动一个函数声明的forms:
function doSomething() { }
…并且不能有没有函数名称的函数语句。
函数expression式和函数语句是两个不同的构造,它们以非常不同的方式处理。 不幸的是,语法几乎是相同的,所以这不仅仅是程序员的困惑,即使parsing器也难以分辨你的意思!
紧跟着安迪·休姆(Andy Hume)和其他人所说的话:
围绕匿名函数的“()”是ECMA规范第11.1.6节中定义的“分组操作符”: http : //www.ecma-international.org/publications/files/ECMA-ST/Ecma-262 .pdf 。
逐字从文档:
11.1.6分组操作员
生产PrimaryExpression :( Expression )的计算方法如下:
- 返回评估expression式的结果。 这可能是参考types。
在这种情况下,函数被视为一个expression式。
关于这个问题的几点考虑:
-
括号:
浏览器(引擎/parsing器)将关键字function与
[optional name]([optional parameters]){...code...}
所以在像function(){}()这样的expression式中,最后一个括号是没有意义的。
现在想想
name=function(){} ; name() !?
是的,第一对括号强制匿名函数变成variables(存储的expression式),然后启动评估/执行
所以(函数(){} )()是有道理的
- 实用程序:?
1,用于在加载时执行一些代码,并将所使用的variables与页面的其余部分隔离,特别是在可能出现名称冲突时;
2用evalreplace(“string”)
(new Function("string"))()
3将“ = ?: ”运算符换成长码,例如:
result = exp_to_test ? (function(){... long_code ...})() : (function(){...})();
第一个括号是,如果你愿意,操作的顺序。 围绕函数定义的括号组的“结果”是函数本身,实际上是第二组圆括号执行的。 至于为什么它是有用的,我不足够的Javascript向导有任何想法。 :P
看到这个问题 。 如果您使用函数名称,则第一组括号不是必需的,但是无名称函数需要此构造,并且括号用于让编码人员在浏览代码时意识到他们正在查看自调用函数(请参阅一个博客的最佳- 实践build议 )。