立即执行函数、闭包
立即执行函数
立即执行函数,就是为了做一个局部变量。
!function () {
var abc = 100
function hehe() {
console.log(abc)
}
hehe()
}.call()
// 立即执行实现了局部变量
闭包
闭包,就是有一个数据和一个操作数据的函数,只把函数暴露出来给外面的人使用。
function bibao() {
var abc = 100
function hehe() {
console.log(abc += 1)
}
return hehe
}
var usebibao = bibao()
usebibao()
// usebibao 接收 bibao() 调用后 返回的 hehe函数,然后 usebibao() 调用 等于 hehe() 调用。
// 于是,闭包把 hehe 函数暴露出去给外面的人使用,外面的人可以通过hehe函数操作变量abc+1,但是却读取不到abc(因为abc是局部变量)。
立即执行函数+闭包
立即执行函数+闭包,就是有一个数据和一个操作数据的函数,把函数挂在window上给外面的人使用。
!function () {
var abc = 100
window.hehe = function () {
console.log(abc += 1)
}
}.call();
// !function (){}.call() 是立即执行函数,是为了做局部变量。
// 变量abc + 使用这个变量的函数 = 闭包
// 闭包的函数赋值给window.hehe,是为了暴露出来给被人使用这个函数。
// 于是,别人能通过window.hehe来操作abc的数据+1,但是却不知道abc的值,实现了隐藏数据的作用。
来看一个例子
崩崩崩.html
<script src="充值.js"></script>
<script src="查询余额.js"></script>
充值.js
!function () {
var player = {
name: '空中劈叉的清洁工',
money: 100
}
window.charge = function () {
player.money += 1
return player.money
}
}.call();
// player是局部变量,window.charge是全局变量。
查询余额.js
!function () {
var newMoney = window.charge()
console.log(newMoney)
}.call();
// 不知道player,但是能操作play的money充值。
为了局部变量而使用立即执行函数
网页要实现模块化
<script src="充值.js"></script>
<script src="查询余额.js"></script>
不能使用全局变量
// 充值.js
var player = 'sakura'
// 查询余额.js
var player = 'mei'
// 充值.js 和 查询余额.js 都使用了全局变量 player,它们互相覆盖,冲突了。
要使用局部变量,ES5里只有函数有局部变量
function () {
var player = '空中劈叉的清洁工'
}.call()
// player是局部变量,函数也是匿名函数,完美!
但是 chrome 浏览器 会报错,语法错误,试出来一种方法不报错
!function () {
var player = '空中劈叉的清洁工'
}.call()
// 在函数前面加!就行
更多解决 chrome浏览器 报语法错误的方法:
(function(){alert('我是匿名函数')} ()) // 用括号把整个表达式包起来
(function(){alert('我是匿名函数')}) () //用括号把函数包起来
!function(){alert('我是匿名函数')}() // 求反,我们不在意值是多少,只想通过语法检查。
+function(){alert('我是匿名函数')}()
-function(){alert('我是匿名函数')}()
~function(){alert('我是匿名函数')}()
void function(){alert('我是匿名函数')}()
new function(){alert('我是匿名函数')}()
为了隐藏数据细节而使用闭包
充值.js
!function () {
var player = {
name: '空中劈叉的清洁工',
money: 100
}
window.charge = function () {
player.money += 1
return player.money
}
}.call();
// 只暴露window.charge,不暴露 player。
// 变量player + 使用这个变量的函数 = 闭包
查询余额.js
!function () {
var newMoney = window.charge()
console.log(newMoney)
}.call();
// 不知道player,但是能通过window.charge操作player的money充值。
立即执行函数+闭包
总结
!function () {
var player = {
name: '空中劈叉的清洁工',
money: 100
}
window.charge = function () {
player.money += 1
return player.money
}
}.call();
// !function (){}.call() 是立即执行函数,是为了做局部变量。
// 变量player + 使用这个变量的函数 = 闭包
// 闭包的函数赋值给window.charge,是为了暴露出来给被人使用这个函数。
// 于是,别人能通过window.charge来操作player的数据+1,但是却不知道player的值,实现了隐藏数据的作用。
一个著名的面试题
var liList = ul.getElementsByTagName('li')
for(var i=0; i<6; i++){
liList[i].onclick = function(){
alert(i) // 为什么 alert 出来的总是 6,而不是 0、1、2、3、4、5
}
}
为什么 alert 的总是 6 呢,因为 i 是贯穿整个作用域的,而不是给每个 li 分配了一个 i。
alert(i) //这里的i一直在遍历的过程中从0变到5,最后停在5.
那么怎么解决这个问题呢?用立即执行函数给每个 li 创造一个独立作用域即可(当然还有其他办法):
var liList = ul.getElementsByTagName('li')
for(var i=0; i<6; i++){
!function(xxx){
liList[xxx].onclick = function(){
alert(xxx) // 0、1、2、3、4、5
}
}(i)
}
在立即执行函数执行的时候,i 的值被赋值给 xxx,此后 xxx 的值一直不变。
i 的值从 0 变化到 5,对应 6 个立即执行函数,这 6 个立即执行函数里面的 xxx 「分别」是 0、1、2、3、4、5。