0%

闭包

函数A的返回值为函数B,在函数A外面可以通过函数B来访问函数A里的局部变量。

变量污染

变量污染就是全局变量滥用,造成报错,覆盖等问题;简单讲就是使用了相同的标识符声明了全局变量,var关键字声明相同的变量名会覆盖,let、const重复声明相同的变量名会直接报错;

  • var 可以声明提升 可以重复声明 定义的变量是全局变量
  • const 、let可以声明块级作用域
  • const声明时必须赋值

闭包函数

1
2
3
4
5
6
7
8
function A(){
var i = 1;
return function B(){
console.log(i);
}
}

A()();

在A函数中定义一个B函数,通过B函数调用A的局部变量i.

所以闭包就是 函数A的返回值为函数B,在函数A外面可以通过函数B来访问函数A里的局部变量i

闭包常常用来「间接访问一个变量」。换句话说,「隐藏一个变量」。

因为如果是全局变量,容易被改,如果是局部变量,别人又访问不到。

1
2
3
4
5
6
7
8
9
10
11
12
13
function xxx(){
var lives = 30
var bug = 'salkdjaslkdjaslkjd...100MB' // IE bug
function die(){
lives -= 1
return lives
}
return die
}

var dieFn = xxx()
// here
var currentLives = dieFn()

闭包造成内存泄露?

内存泄露是指你用不到(访问不到)的变量,依然占居着内存空间,不能被再次利用起来。

闭包里面的变量明明就是我们需要的变量(lives),所以不是内存泄露

为何有人说是?

因为 IE。IE 有 bug,IE 在我们使用完闭包之后,依然回收不了闭包里面引用的变量。

立即执行函数

声明一个匿名函数,立即执行它,就是立即执行函数

1
2
3
4
!function (){
var lives = 30
console.log(lives)
}.call()

感叹号可以换成 + - ~ 等符号,也可以换成括号。

那为什么要有这么个东西(好麻烦)

只有一个作用:创建一个独立的作用域。

这个作用域里面的变量,外面访问不到(即避免「变量污染」)。

这个作用不就恰恰是闭包所需要的吗!!!

所以之前的函数可以写成

1
2
3
4
5
6
7
8
9
!function xxx(){
var lives = 30
var bug = 'salkdjaslkdjaslkjd...100MB' // IE bug
function die(){
lives -= 1
return lives
}
return die
}.call()

举例

1
2
3
4
5
6
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
}
}

因为在点击之前i早变成了6,每个监听的元素都为6。

那么怎么解决这个问题呢?用立即执行函数给每个 li 创造一个独立作用域即可

1
2
3
4
5
6
7
8
var liList = ul.getElementsByTagName('li')
for(var i=0; i<6; i++){
!function(ii){
liList[ii].onclick = function(){
alert(ii) // 0、1、2、3、4、5
}
}(i)
}

在立即执行函数执行的时候,i 的值被赋值给 ii,此后 ii 的值一直不变。

i 的值从 0 变化到 5,对应 6 个立即执行函数,这 6 个立即执行函数里面的 ii 「分别」是 0、1、2、3、4、5。

您的支持将帮助我们前进

欢迎关注我的其它发布渠道