立即执行函数
写代码时尽量不要使用全局变量,因为很可能会相互覆盖
在 java 语言中我们可以用 { } 将代码包裹起来,使它们成为局部变量
但是这在 ES5 中不行,因为 var 有变量提升
{
var a = 1;
}
// 上面代码等同于
var a
{
a = 1;
}
于是ES6 里面引入了 let 的概念,就有了块级作用域
解决了这个问题,立即执行函数 似乎就变得不那么必要了
{
let a = 1;
}
a
// Uncaught ReferenceError: a is not defined
但是了解 立即执行函数 可以让我们初学者更好得理解函数表达式、变量提升等的概念。
ES5 里面,没有块级作用域,只有函数(函数作用域)可提供局部变量环境
于是我们声明一个 function xxx
,然后 xxx.call()
function xxx(){
var a = 1;
}.call()
但是这个时候 xxx 也是全局变量(全局函数)
所以我们不能给这个函数名字,即需要使用匿名函数
function(){
var a = 1;
}.call()
// Uncaught SyntaxError: Unexpected token (
但是这在 Chrome 里会报错,js 语法错误
这是由于浏览器认为这是一个函数声明
解决办法:让浏览器去解析这个函数表达式
如给函数取反
! function(){
var a = 1;
}.call()
// 我们不在乎这个匿名函数的返回值,所以加个 ! 取反没关系
类似的还有
+function(){}()
-function(){}()
~function(){}()
void function(){}()
new function(){}()
// function(){}() === function(){}.call()
//用 .call() 更清楚
如果实在不想改变函数返回值,也可以用圆括号
(function(){}).call()
(function(){}.call())
但是方法会有不好的情况:如果括号前面有东西
a
(function(){}).call()
//等价于
a().call()
//这不是我们想要的
//同理
a
(function(){}.call())
//等价于.
a()
你也可以用一个随机变量名函数而不用匿名函数,永远都不会变量污染的那种变量(这种方法好吗?)
function ada231231284u3lkda(){
var a = 1;
}.call()
当然最推荐的还是用取反 !,这就好像是个警示:我要开始用立即执行函数 了
立即执行函数就是
- 声明一个匿名函数
- 马上调用这个匿名函数
立即执行函数 达到了局部变量的效果,外面访问不到立即执行函数里面的变量(避免变量污染)
但有时候我们需要访问立即执行函数 里面的内容,怎么办?
最简单的方法是直接用全局变量 window
! function(){
var a = window.a = {
n: 1
}
}.call()
// 另一个立即执行函数通过 window.a 访问
! function(){
var b = window.a
console.log(a)
}.call() // {n: 1}
.我们还可以在 立即执行函数 里面使用闭包来隐藏 a
! function(){
var a = {
n: 1
}
// 声明一个匿名函数保存于 window.nAdd1
window.nAdd1 = function(){
a.n += 1
// return 新的 a.n
return a.n
}
}.call()
// 匿名函数可以操作函数外面的变量 a ,这就是闭包
// 另一个立即执行函数通过 window 访问
! function(){
var b = window.nAdd1()
console.log(newN)
}.call() // 2
立即调用函数表达式使得 a 成为局部变量而无法被外部访问
闭包使得匿名函数可以操作 a
window.nAdd1 保存了匿名函数的地址
任何地方都可以使用 window.nAdd1
=> 任何地方都可以使用 window.nAdd1 操作 a,但是不能直接访问 a
这就是 window 和闭包联合作用的效果
闭包
function fn(){
var a = {
n: 1
}
function fn2(){
a.n += 1
return a.n
}
return fn2
}
var fn1 = fn()
fn1() // 2
// 上面代码其实就是
(function(){
var a = {
n: 1
}
return function(){
a.n += 1
return a.n
}
}.call()) // IIFE
.call()// 2
现在明白了为什么闭包一般在立即执行函数里出现
立即执行函数 提供局部变量的环境,才有闭包的用武之地
return 的作用
上面代码中的 return 和 window 的作用一样,是为了让外部能够访问函数作用域内部的函数,当然 return a.n 的作用也是如此
相关参考:
方应杭:「每日一题」什么是立即执行函数?有什么作用?
方应杭:「每日一题」JS 中的闭包是什么?