Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JavaScript浅析 -- IIFE立即执行函数表达式 #7

Open
luoshaoxiong opened this issue Sep 4, 2018 · 0 comments
Open

JavaScript浅析 -- IIFE立即执行函数表达式 #7

luoshaoxiong opened this issue Sep 4, 2018 · 0 comments

Comments

@luoshaoxiong
Copy link
Owner

一、什么是IIFE?

所谓IIFE(Immediately-Invoked Function Expression)翻译过来就是立即执行函数表达式。其实就是

  1. 声明了一个函数。
  2. 立即执行这个函数。

他有好多种写法,如下代码就是经典的写法:

(function() { console.log('立即执行') })()

如上,前面是一个函数,然后调用函数是‘函数名()’,所以后面加()执行该函数。这个比较好理解,那前面那个为啥要加括号呢?不加可以不?我们来试试:

function() { console.log('立即执行') }() // Uncaught SyntaxError: Unexpected token (

结果是报错Uncaught SyntaxError: Unexpected token (,为啥呢?其实因为js解释代码的时候遇到function会认为是一个函数声明,而声明函数却没有找到函数名,所以遇到第一个左括号就报错了。接着我们加上函数名修改如下:

function func() { console.log('立即执行') }() // Uncaught SyntaxError: Unexpected token )

还是报错Uncaught SyntaxError: Unexpected token ),好在错误变了,不过这次又是为啥?其实因为前面的函数声明包含函数名已经是一个完整的语句了,所以后面的()又另做为一个语句。相当于如下代码:

function func() { console.log('立即执行') }
()

而分组操作符()中的表达式又不能为空,所以是遇到最后一个右括号才报的错。那怎样才能让两者并成一个语句从而实现函数的执行呢?

为了解决上面的两个问题,只要让其变成表达式,加个括号就行了,因为括号内部不能有语句所以会认为是一个表达式。有如下两种写法:

  • (function func(){})()
  • (function func(){}())

其原理都是一样的,都是为了让其变成一个表达式。而其实让他变成表达式的写法不止上面两种,上面两种是比较经典易读的写法。还有如下几种,原理都是一样的:

// 运算符直接转表达式法
var i = function(){ console.log('立即执行') }();
!function(){ console.log('立即执行') }();
~function(){ console.log('立即执行') }();
-function(){ console.log('立即执行') }();
+function(){ console.log('立即执行') }();

// 解析器在遇到& || ,等操作符时,会把两边默认为表达式。
// 但注意交换位置就不行,因为如果把function放在前面则还是会认为是声明
true & function(){ console.log('立即执行') }();
0, function(){ console.log('立即执行') }();

// 以及new
new function(){ console.log('立即执行') }
new function(){ console.log('立即执行') }() // 带参数

二、IIFE有啥用?

先来看个例子,如下声明了一个变量i并输出:

var i = 0;
console.log(i);

但是这样做有时候会有一个问题,在这个全局作用域下声明的i会影响到整个作用域(全局污染),也就是整个全局作用域下的i都变成了0,而我们只是单纯想在这里可用,应该怎么做呢?在Js(ES6之前)里只分为全局作用域和局部作用域 ,局部作用域一般是通过函数来创建一个单独的作用域,这个作用域下只有函数内可用。所以将上面改写如下:

function a() {
    var i = 0;
    console.log(i);
}
a();

这样的话,i就只在函数a里面才有效。可是。。。却多出来一个变量a,还是污染了全局。其实这个a也是可以避免的,因为我们声明了这个函数只是想利用他的局部作用域而已,声明完就立马执行了,何必起个名字呢。所以再进一步改写如下:

(function() {
    var i = 0;
    console.log(i);
})()

这样立即执行函数表达式就诞生了,神奇吧?(其实还是挺鸡肋的,代码写的这么复杂只是想创建一个不污染全局的变量而已,在ES6之后有了块级作用域和let等,这些问题得到了改善)。

所以经过上面的例子,我们大概就能体会立即执行函数表达式有啥用了。简单来说:

  • IIFE的作用就是创建一个独立的作用域。在这个作用域里面的变量只有其内可以访问,从而避免变量污染
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant