Pre*_*gar 364 javascript syntax anonymous-function
你能解释一下JavaScript中封装的匿名函数语法背后的原因吗?为什么这样做:(function(){})();但这不是:function(){}();?
在JavaScript中,可以创建一个这样的命名函数:
function twoPlusTwo(){
alert(2 + 2);
}
twoPlusTwo();
Run Code Online (Sandbox Code Playgroud)
您还可以创建匿名函数并将其分配给变量:
var twoPlusTwo = function(){
alert(2 + 2);
};
twoPlusTwo();
Run Code Online (Sandbox Code Playgroud)
您可以通过创建匿名函数来封装代码块,然后将其包装在括号中并立即执行:
(function(){
alert(2 + 2);
})();
Run Code Online (Sandbox Code Playgroud)
这在创建模块化脚本时非常有用,可以避免使当前作用域或全局作用域混乱,并且可能存在冲突的变量 - 例如Greasemonkey脚本,jQuery插件等.
现在,我理解为什么会这样.括号包含内容并仅公开结果(我确定有更好的方法来描述),例如with (2 + 2) === 4.
但我不明白为什么这也不起作用:
function(){
alert(2 + 2);
}();
Run Code Online (Sandbox Code Playgroud)
你能解释一下吗?
CMS*_*CMS 399
它不起作用,因为它被解析为a FunctionDeclaration,并且函数声明的名称标识符是必需的.
当用括号括起它时,它被评估为a FunctionExpression,并且可以命名或不命名函数表达式.
FunctionDeclaration看起来像这样的语法:
function Identifier ( FormalParameterListopt ) { FunctionBody }
Run Code Online (Sandbox Code Playgroud)
并且FunctionExpressions:
function Identifieropt ( FormalParameterListopt ) { FunctionBody }
Run Code Online (Sandbox Code Playgroud)
如您所见,Identifier(Identifier opt)令牌FunctionExpression是可选的,因此我们可以使用没有定义名称的函数表达式:
(function () {
alert(2 + 2);
}());
Run Code Online (Sandbox Code Playgroud)
或命名函数表达式:
(function foo() {
alert(2 + 2);
}());
Run Code Online (Sandbox Code Playgroud)
括号(正式称为分组运算符)只能包含表达式,并且会计算函数表达式.
这两个语法产生可能不明确,它们看起来完全相同,例如:
function foo () {} // FunctionDeclaration
0,function foo () {} // FunctionExpression
Run Code Online (Sandbox Code Playgroud)
解析器知道它是a FunctionDeclaration还是a FunctionExpression,具体取决于它出现的上下文.
在上面的示例中,第二个是表达式,因为逗号运算符也可以只处理表达式.
另一方面,FunctionDeclarations实际上只能出现在所谓的" Program"代码中,这意味着代码在全局范围之外,在FunctionBody其他函数内部.
应该避免块内的函数,因为它们可能导致不可预测的行为,例如:
if (true) {
function foo() {
alert('true');
}
} else {
function foo() {
alert('false!');
}
}
foo(); // true? false? why?Run Code Online (Sandbox Code Playgroud)
上面的代码实际上应该生成一个SyntaxError,因为一个Block只能包含语句(并且ECMAScript规范没有定义任何函数语句),但是大多数实现都是容忍的,并且只需要第二个函数,即警报'false!'.
Mozilla实现-Rhino,SpiderMonkey, - 具有不同的行为.它们的语法包含一个非标准的 Function语句,这意味着该函数将在运行时进行评估,而不是在分析时进行评估,就像FunctionDeclarations一样.在这些实现中,我们将定义第一个函数.
可以用不同的方式声明函数,比较以下内容:
1-使用分配给变量multiply的Function构造函数定义的函数:
var multiply = new Function("x", "y", "return x * y;");
Run Code Online (Sandbox Code Playgroud)
2-名为multiply的函数的函数声明:
function multiply(x, y) {
return x * y;
}
Run Code Online (Sandbox Code Playgroud)
3-分配给变量multiply的函数表达式:
var multiply = function (x, y) {
return x * y;
};
Run Code Online (Sandbox Code Playgroud)
4-命名函数表达式func_name,分配给变量multiply:
var multiply = function func_name(x, y) {
return x * y;
};
Run Code Online (Sandbox Code Playgroud)
nat*_*e75 48
虽然这是一个古老的问题和答案,但它讨论了一个主题,直到今天仍然让许多开发人员进行循环.我无法计算我采访过的JavaScript开发人员候选人的数量,他们无法告诉我函数声明和函数表达式之间的区别,以及谁不知道立即调用的函数表达式是什么.
不过,我想提一下,一个非常重要的事情是Premasagar的代码片段即使给了它一个名字标识符也行不通.
function someName() {
alert(2 + 2);
}();
Run Code Online (Sandbox Code Playgroud)
这不起作用的原因是JavaScript引擎将此解释为函数声明,后跟一个完全不相关的不包含表达式的分组运算符,分组运算符必须包含表达式.根据JavaScript,上面的代码片段相当于下面的代码片段.
function someName() {
alert(2 + 2);
}
();
Run Code Online (Sandbox Code Playgroud)
我想指出的另一件事可能对某些人有用,就是你为函数表达式提供的任何名称标识符在代码上下文中都是无用的,除非在函数定义本身内.
var a = function b() {
// do something
};
a(); // works
b(); // doesn't work
var c = function d() {
window.setTimeout(d, 1000); // works
};
Run Code Online (Sandbox Code Playgroud)
当然,在调试代码时使用带有函数定义的名称标识符总是有用的,但这完全是另一回事...... :-)
Ori*_*iol 15
已经发布了很好的答案.但是我想要注意函数声明返回一个空的完成记录:
FunctionDeclaration:
functionBindingIdentifier(FormalParameters){FunctionBody}
- 返回NormalCompletion(空).
这个事实并不容易观察,因为尝试获取返回值的大多数方法都会将函数声明转换为函数表达式.但是,eval显示它:
var r = eval("function f(){}");
console.log(r); // undefinedRun Code Online (Sandbox Code Playgroud)
调用空完成记录毫无意义.这就是为什么function f(){}()不能工作的原因.实际上JS引擎甚至没有尝试调用它,括号被认为是另一个语句的一部分.
但是如果你将函数包装在括号中,它就变成了一个函数表达式:
var r = eval("(function f(){})");
console.log(r); // function f(){}Run Code Online (Sandbox Code Playgroud)
函数表达式返回一个函数对象.因此你可以称之为:(function f(){})().
在javascript中,这称为立即调用函数表达式(IIFE).
为了使它成为函数表达式,你需要:
用()括起来
在它之前放置一个void运算符
将其分配给变量.
否则它将被视为函数定义,然后您将无法通过以下方式同时调用/调用它:
function (arg1) { console.log(arg1) }();
Run Code Online (Sandbox Code Playgroud)
以上将给你错误.因为您只能立即调用函数表达式.
这可以通过以下两种方式实现:方式1:
(function(arg1, arg2){
//some code
})(var1, var2);
Run Code Online (Sandbox Code Playgroud)
方式2:
(function(arg1, arg2){
//some code
}(var1, var2));
Run Code Online (Sandbox Code Playgroud)
方式3:
void function(arg1, arg2){
//some code
}(var1, var2);
Run Code Online (Sandbox Code Playgroud)
方式4:
var ll = function (arg1, arg2) {
console.log(arg1, arg2);
}(var1, var2);
Run Code Online (Sandbox Code Playgroud)
以上都会立即调用函数表达式.
| 归档时间: |
|
| 查看次数: |
70502 次 |
| 最近记录: |