闭包所引起的问题有三点:this指向、变量的作用域,内存泄露。
闭包定义:函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起构成闭包(closure)。
定义可以理解,调用闭包其实就是调用函数。当程序在调用某个函数时,做了一下的工作:准备执行环境,初始函数作用域链和arguments参数对象。
再来看这三个问题:
1.引用的变量可能发生变化
function outer() {
var result = [];
for (var i = 0; i<10; i++){
result.[i] = function () {
console.info(i)
}
}
return result
}
可以改成
function outer() {
var result = [];
for (var i = 0; i<10; i++){
result.[i] = function (num) {
return function() {
console.info(num); // 此时访问的num,是上层函数执行环境的num,数组有10个函数对象,每个对象的执行环境下的number都不一样
}
}(i)
}
return result
}
2.this的指向问题
var object = {
name: "Iris",
getName: function() {
return function() {
console.info(this.name)
}
}
}
object.getName()() // underfined
// 因为里面的闭包函数是在window作用域下执行的,也就是说,this指向windows
可以改成
var object = {
name: "Iris",
getName: function() {
let _this = this;
return function() {
console.info(_this.name)
}
}
}
object.getName()() // Iris
3.内存泄漏
function showId() {
var el = document.getElementById("app")
el.onclick = function(){
aler(el.id) // 这样会导致闭包引用外层的el,当执行完showId后,el无法释放
}
}
// 改成下面
function showId() {
var el = document.getElementById("app")
var id = el.id
el.onclick = function(){
aler(id) // 这样会导致闭包引用外层的el,当执行完showId后,el无法释放
}
el = null // 主动释放el
}
结论:
前两个问题——this指向、变量的作用域:是由于函数执行时,执行环境不同所导致的,一定要注意函数调用时的执行环境和环境的作用域链;
(ps:这里顺便说下this指向的问题,因为道理和这个类似:this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象)
最后一个问题——内存泄露是因为函数中变量相互引用,造成变量无法回收