我想知道这是什么意思:
(function () {
})();
这是在说document。onload吗?
我想知道这是什么意思:
(function () {
})();
这是在说document。onload吗?
当前回答
它声明了一个匿名函数,然后调用它:
(function (local_arg) {
// anonymous function
console.log(local_arg);
})(arg);
其他回答
不,这个构造只是为命名创建了一个作用域。如果你把它分成几部分,你可以看到你有一个外部
(...)();
这是一个函数调用。括号内是:
function() {}
这是一个匿名函数。在构造中使用var声明的所有内容将只在同一构造中可见,并且不会污染全局名称空间。
使用自调用匿名函数的原因是它们永远不应该被其他代码调用,因为它们“设置”了要调用的代码(同时为函数和变量提供了作用域)。
换句话说,它们就像在程序开始时“创建类”的程序。在它们被实例化(自动)之后,唯一可用的函数是匿名函数返回的那些函数。然而,所有其他“隐藏”函数仍然存在,以及任何状态(在作用域创建期间设置的变量)。
非常酷。
TL;DR:表达式可以括在圆括号中,如果函数的表达式和块形式组合在一起,则会与函数调用冲突。
我喜欢反例,因为它们描绘了一幅伟大的逻辑图景,而其他人没有列出任何反例。你可能会问,“为什么浏览器不能看到function(){}(),而只是假设它是一个表达式?”让我们用三个例子来比较这个问题。
var x; //这里fibonacci是一个block函数 函数fibonacci(x) { Var值= x < 2 ?X: fibonacci(X -1) + fibonacci(X -2); if (x === 9) console.log("The " + x + "th fibonacci is: " + value); 返回值; } (x = 9); console.log(" x的值:" + x); Console.log ("fibonacci is a(n) ")+ typeof fibonacci);
当我们将函数转换为表达式时,观察事情是如何变化的。
var x; //这里fibonacci是一个函数表达式 函数fibonacci(x) { Var值= x < 2 ?X: fibonacci(X -1) + fibonacci(X -2); if (x === 9) console.log("The " + x + "th fibonacci is: " + value); 返回值; }) (x = 9); console.log(" x的值:" + x); Console.log ("fibonacci is a(n) ")+ typeof fibonacci);
当你使用not-operator而不是圆括号时,也会发生同样的事情,因为这两个操作符都将语句转换为表达式:
var x; //这里fibonacci是一个函数表达式 ! 函数fibonacci(x) { Var值= x < 2 ?X: fibonacci(X -1) + fibonacci(X -2); if (x === 9) console.log("The " + x + "th fibonacci is: " + value); 返回值; } (x = 9); console.log(" x的值:" + x); Console.log ("fibonacci is a(n) ")+ typeof fibonacci);
通过将函数转换为表达式,它由它下面的两行(x = 9)执行。由于表达式函数和块函数的行为是分开的,所以这两个例子都运行得很好,没有歧义(规范方面)。
名字的作用域
另一个重要的观察是,命名块函数对整个作用域可见,而函数表达式只对其本身可见。换句话说,fibonacci只对第一个示例中的最后一个console.log是块时可见。在这三个例子中,fibonacci对自身是可见的,允许fibonacci调用自身,这是递归。
箭头功能
逻辑的另一个方面是箭头函数。如果块函数和表达式函数的定义合并在一起,规范将不得不包括箭头函数的任意规则和例外:
函数hello() {console.log(" hello World")} (x) => console.log("hello " + x) console.log("如果你正在阅读,没有发生错误");
虽然函数块工作正常,但函数表达式后面跟着箭头函数会产生语法错误:
! 函数hello() {console.log(" hello World")} (x) => console.log("hello " + x) console.log("如果你正在阅读,没有发生错误");
这里,第二行的(x)是调用前一行的函数还是箭头函数的函数参数是不明确的。
请注意,箭头函数多年来确实符合ECMAScript标准,在语言的初始设计中并不是一个因素;我的观点是,表达式函数和块函数之间的区别有助于JavaScript语法更有逻辑性和连贯性。
它是一个立即调用的函数表达式,简称IIFE。它在创建后立即执行。
它与任何事件的任何事件处理程序(例如document.onload)无关。 考虑第一对括号中的部分:(function(){})();....它是一个正则函数表达式。然后看最后一对(function(){})();,它通常被添加到表达式中来调用函数;在这种情况下,我们之前的表达式。
当试图避免污染全局名称空间时,通常使用此模式,因为在IIFE中使用的所有变量(像在任何其他正常函数中一样)在其作用域之外是不可见的。 这可能就是为什么您将此结构与window的事件处理程序混淆的原因。Onload,因为它经常被这样使用:
(function(){
// all your code here
var foo = function() {};
window.onload = foo;
// ...
})();
// foo is unreachable here (it’s undefined)
Guffa建议的更正:
函数在创建后立即执行,而不是在解析后执行。整个脚本块在执行其中的任何代码之前都会被解析。此外,解析代码并不自动意味着它被执行,例如,如果IIFE在函数内部,那么直到函数被调用,它才会被执行。
更新 因为这是一个非常流行的话题,值得一提的是,IIFE也可以用ES6的箭头函数来编写(就像Gajus在评论中指出的那样):
((foo) => {
// do something with foo here foo
})('foo value')
它被称为IIFE -立即调用函数表达式。下面是一个例子来展示它的语法和用法。它用于将变量的使用范围限定在函数之前,而不是超出函数。
(function () {
function Question(q,a,c) {
this.q = q;
this.a = a;
this.c = c;
}
Question.prototype.displayQuestion = function() {
console.log(this.q);
for (var i = 0; i < this.a.length; i++) {
console.log(i+": "+this.a[i]);
}
}
Question.prototype.checkAnswer = function(ans) {
if (ans===this.c) {
console.log("correct");
} else {
console.log("incorrect");
}
}
var q1 = new Question('Is Javascript the coolest?', ['yes', 'no'], 0);
var q2 = new Question('Is python better than Javascript?', ['yes', 'no', 'both are same'], 2);
var q3 = new Question('Is Javascript the worst?', ['yes', 'no'], 1);
var questions = [q1, q2, q3];
var n = Math.floor(Math.random() * questions.length)
var answer = parseInt(prompt(questions[n].displayQuestion()));
questions[n].checkAnswer(answer);
})();