在一個JS文件中,如果文件太大又沒有使用模塊化的方法的話,全局變量就會變的錯綜復雜,當JS代碼量達到一定程度,彼此之間的關(guān)系會變的復雜,更加難以維護。這個時候就需要為一部分代碼單獨創(chuàng)建一個作用域,而為了使這個封閉作用域和其它封閉作用域進行溝通,就產(chǎn)生了閉包及其使用。
一、消除全局變量的兩種常見方法
- 立即執(zhí)行函數(shù)
!function (){
var $topbar = $('#topbar')
$topbar.on('click',function(){
console.log('topbar')
})
}()
這樣,$topbar就成了一個局部變量。
- ES6語法創(chuàng)建局部變量
{
let $banner = $('#banner')
$banner.on('click',function(){
console.log('banner')
})
}
二、由立即執(zhí)行函數(shù)構(gòu)建的孤島,彼此之間如何溝通?
還是借助全局變量
!function (){
var $topbar = $('#topbar')
$topbar.on('click',function(){
console.log('topbar')
})
var name = 'xiaoming'
window.name = name
}()
!function(){
var $banner = $('#banner')
$banner.on('click',function(){
console.log('banner')
})
window.name = 'xiaoqiang'
console.log(name)
}()
但是上面的這種方法的問題在于,當我把一個局部變量暴露成全局變量以后,其它作用域就可以修改這個全局變量。那么,如何讓變量暴露出去可以讓其它作用域訪問但是卻不能修改呢?
方法如下:
!function (){
var $topbar = $('#topbar')
$topbar.on('click',function(){
console.log('topbar')
})
var user = {
name: 'xiaoming',
age: 18
}
window.userGetter = {
nameGetter: function(){ return user.name },
ageGetter: function(){ return user.age }
}
}()
!function(){
var $banner = $('#banner')
$banner.on('click',function(){
console.log('banner')
})
console.log(window.userGetter.nameGetter())
console.log(window.userGetter.ageGetter())
}()
雖然還是暴露了一個全局對象,但是這樣就達到了其它作用域無法修改的要求
二、閉包
好了,到這里了我們就來理解一下什么是閉包?閉包就是函數(shù)和函數(shù)內(nèi)部能訪問到的變量的總和。
上面舉的例子其實已經(jīng)多次用到了閉包:
!function (){
var user = {
name: 'xiaoming',
age: 18
}
window.userGetter = {
nameGetter: function(){ return user.name },
ageGetter: function(){ return user.age }
}
}()
在這個例子里, function(){ return user.name }和user.name就是一個閉包。。。(函數(shù)和函數(shù)內(nèi)部能訪問到的變量的總和),之所以把它掛到全局變量上,是為了讓其它作用域能夠使用這個閉包。
三、閉包再舉例
function a(){
var b = 1
function xxx(){
return b += 1
}
return xxx
}
var c = a()
c()
之所以要在a里再返回一個函數(shù),是為了讓其它作用域能夠使用這個閉包,它暴露了一些東西讓其它人來使用,但是又不能更改原來的東西。
除了這樣,下面這樣也是行的,只是使用閉包的方法不一樣,一個是通過返回函數(shù)使用,一個是通過掛到全局變量上使用。
function a(){
var b = 1
function xxx(){
return b += 1
}
window.xxx = xxx
}
a()
xxx()
連上之前的例子,這三個例子,背下來?。?!