在一个JS文件中,如果文件太大又没有使用模块化的方法的话,全局变量就会变的错综复杂,当JS代码量达到一定程度,彼此之间的关系会变的复杂,更加难以维护。这个时候就需要为一部分代码单独创建一个作用域,而为了使这个封闭作用域和其它封闭作用域进行沟通,就产生了闭包及其使用。
一、消除全局变量的两种常见方法
- 立即执行函数
!function (){
var $topbar = $('#topbar')
$topbar.on('click',function(){
console.log('topbar')
})
}()
这样,$topbar就成了一个局部变量。
- ES6语法创建局部变量
{
let $banner = $('#banner')
$banner.on('click',function(){
console.log('banner')
})
}
二、由立即执行函数构建的孤岛,彼此之间如何沟通?
还是借助全局变量
!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())
}()
虽然还是暴露了一个全局对象,但是这样就达到了其它作用域无法修改的要求
二、闭包
好了,到这里了我们就来理解一下什么是闭包?闭包就是函数和函数内部能访问到的变量的总和。
上面举的例子其实已经多次用到了闭包:
!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就是一个闭包。。。(函数和函数内部能访问到的变量的总和),之所以把它挂到全局变量上,是为了让其它作用域能够使用这个闭包。
三、闭包再举例
function a(){
var b = 1
function xxx(){
return b += 1
}
return xxx
}
var c = a()
c()
之所以要在a里再返回一个函数,是为了让其它作用域能够使用这个闭包,它暴露了一些东西让其它人来使用,但是又不能更改原来的东西。
除了这样,下面这样也是行的,只是使用闭包的方法不一样,一个是通过返回函数使用,一个是通过挂到全局变量上使用。
function a(){
var b = 1
function xxx(){
return b += 1
}
window.xxx = xxx
}
a()
xxx()
连上之前的例子,这三个例子,背下来!!!