继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

澄清误解,详解JS立即执行函数

恩言
关注TA
已关注
手记 41
粉丝 316
获赞 3231
澄清误解,详解JS立即执行函数

JS只有函数作用域,没有块级作用域。于是,聪明的程序猿们想出来利用函数作用域模仿块

级作用域的“锦囊妙计”,并被广泛使用:

(function (value) {
    alert(value);
}('hello'));

(function (value) {
    alert(value);
})('hello');

! function (value) {
    alert(value);
} ('world');

+ function (value) {
    alert(value);
} ('world');

- function (value) {
    alert(value);
} ('world');

但上面千奇百怪的符号往往令初学者无比困惑。百度到的答案令人遗憾,很多都是曲解,(一个排名很靠前的博客把问题总结为:函数声明、函数表达式、匿名函数的区别,认为函数表达式后面可以加括号立即调用该函数,函数声明不可以。这根本没有理解本质所在)

这也让我在很长的一段时间里对立即执行函数感到迷惘。然而其实在《javascript精粹》和《JavaScript权威指南》中说的很清楚,我写这篇文章的目的所在,正是澄清这个问题。

首先,我们要明确的是,这些写法的目的都是相同的,立即执行里面的匿名函数(以达到闭包等等“不可告人的目的”)

为了解开其中的奥秘,首先让我们明确这些结构的组成部分——表达式

表达式

(1) 函数表达式

函数表达式有点类似于“函数直接量”,其中[]表示可选。

function [funName] () {
  // ... ...
}

函数表达式还可以赋给某个变量

var sayHello = function () { ... ... }

(2) 调用表达式

语法:

函数表达式()

例如:

sayHello('Tom')

这样,会执行sayHello这个函数。也就是说,在函数后面加上()并传递相应的参数就可以执行在函数里定义的语句。

JS的原则

立即调用的函数不需要函数名,直接调用即可,所以很多“聪明人”的代码出现了下面的错误:

function (value) {
    alert(value);
}('hello')

报:Unexpected token ( 错误。错误的原因不在于聪明的程序猿们,因为这的确符合调用表达式的语法。其实,问题的本质在于JS的一项“霸王条款”:

一个语句不能以一个函数表达式开头,因为官方语法假定以单词function开头的语句是一个function语句
(《javascript精粹》114页)

这下答案揭晓了:上面立即调用函数句式的原因正在于此。JS引擎认为以function开头的是函数声明语句,不能是函数调用语句。

下面的代码没有问题,因为语句的最前面并非function:

var index = function () {
    alert('函数表达式执行了!!');
    return 666
} ();

index // =>666

解决问题

解决问题的最简单办法就是不让function出现在语句的最前面。()这个“物美价廉,绿色无公害”的运算符遍成了首选,所以立即执行函数的最常见形式是:

(function (value) {
    alert(value);
}('hello'));

相对而言,!等运算符也行有副作用,而且结果往往令人大吃一惊:

var index = !function () {
    alert('匿名函数执行了!!');
    return 666
} ();

index // =>false

index变为fasle的原因是!为666做了强制转换并取了反。

大师Douglas Crockford的 javascript:the good part (《javascript精粹》)真是一本javascript的绝世秘籍,令人由衷赞叹!!

打开App,阅读手记
8人推荐
发表评论
随时随地看视频慕课网APP