闭包:创建闭包的常见方式,就是在一个函数内部创建另一个函数;例如:①
function createComparisonFunction(propertyName) {
return function(object1, object2) {
const value1 = object1[propertyName]
const value2 = object2[propertyName]
return 'value1: ' + value1 + ';value2:' + value2
}
}
let compareNames = createComparisonFunction('name')
const result = compareNames({ name: 'red' }, { name: 'black' })
console.log(result)
compareNames = null
1、闭包与变量
闭包这种作用域链的配置机制有一个值得注意的副作用,即闭包只能取得函数中任何变量的最后一个值。例子:①
解决方案:我们可以通过创建另一个匿名函数强制让闭包的行为符合预期。例子:②
function createFunctions() {
var result = new Array()
for (var i = 0; i < 10; i++) {
result[i] = function() {
return i
}
}
return result
}
const result1 = createFunctions()
console.log(result1[0](), result1[1](), result1[2]())
function createFunctions2() {
var result = new Array()
for (var i = 0; i < 10; i++) {
result[i] = function(num) {
return num
}(i)
}
return result
}
2、关于this对象
当某个函数被作为某个对象的方法调用时,this等于那个对象;在全局函数中,this等于window。
但是,在闭包中使用this对象也可能会导致一些问题。例子:①
在这个例子中,当执行object2.getNameFun()()时,this最终指向的是window而不是object2
解决方案:把this对象保存在一个闭包能访问到的变量里,就可以让闭包访问到该对象了;(或者通过apply,call)例子:②
var name2 = 'This Window'
var object2 = {
name2: 'My object',
getNameFun: function () {
return function() {
return this.name2
}
}
}
console.log(object2.getNameFun()())
var name21 = 'This Window'
var object21 = {
name21: 'My Object',
getNameFun: function () {
var that = this
return function () {
return that.name21
}
},
getNameApply: function () {
return function () {
return this.name21
}
}
}
console.log(object21.getNameFun()())
console.log(object21.getNameApply()())
var apply21 = object21.getNameApply().apply(object21, [])
console.log(apply21)
3、内存泄漏
具体来说,如果闭包的作用域链中保存着一个HTML元素,那么就意味着该元素将无法被销毁;例子:①
该例子,创建了一个作为element元素事件处理程序的闭包,而这个闭包则又创建了一个循环引用。
由于匿名函数保存了一个对assignHandler()的活动对象的引用,因此就会导致无法减少element的引用数。
只要匿名函数存在,element的引用至少也是1,因此它所占用的内存就永远不会被回收。
解决方案:②
必须要记住:闭包会引用包含函数的整个活动对象,而其中也包含element,即使不直接引用,包含函数的活动对象中也仍然会保存一个引用。
把element设置为null,就能解除对DOM对象的引用
function assignHandler () {
var element = document.getElementById('xxx')
element.onclick = function () {
console.log(element.id)
}
}
function assignHandler2 () {
var element = document.getElementById('xxx')
var id = element.id
element.onclick = function () {
console.log(id)
}
element = null
}