读书笔记:JavaScript——闭包

一、概念
1、闭包是指有权访问另一个函数作用域中的变量的函数。

2、作用域链:

  • 函数创建时,会创建一个预先包含全局变量对象的作用域链,保存在内部的[[scope]]属性;
  • 函数调用时,创建一个执行环境,复制[[scope]]属性中的作用域链构建这个执行环境的作用域链,函数的局部变量对象被创建并推入作用域链前端;
  • 函数内部局部环境的变量对象只在函数执行过程中存在,执行完毕后就会被销毁;
  • 作用域链本质上是一个指向变量对象的指针列表,只引用但不包含变量对象。

二、闭包
存在闭包时,被返回的闭包函数被赋值给了一个全局变量,闭包函数的作用域链一直引用着它外层的函数的活动对象,这个函数执行完就不会被销毁,除非解除对闭包函数的引用,除了全局作用域外的作用域才会被销毁。

function compare (attr) {
	return function (obj1, obj2) {//闭包函数
		var val1 = obj1[attr]
		var val2 = obj2[attr]
		return val1-val2
	}
}
let compare1 = compare('name')

compare函数赋值给compare1,compare1引用compare内部返回的匿名函数,此匿名函数作用域链包含compare的变量对象

const result = compare1('diana', 'js')

调用compare1,可以访问compare作用域链

compare1 = null

解除对匿名函数的引用,销毁其作用域链

三、闭包与变量
1、一个典型的闭包函数问题

function foo () {
	var result = new Array()
	for (var i = 0; i < 10; i++) {
		result[i] = function () {//闭包函数
			return i
		}
	}
	return result
}
var foo1 = foo()

foo()函数执行,返回result给foo1

var res1 = foo1[2]

通过闭包调用foo()函数变量,此时foo的循环已执行完毕,变量i=10

console.log(res1())//10

闭包只能取得包含函数中任何变量的最终值

分析:
1)首先var foo1 = foo(),函数foo()依次执行函数内的代码,包括for循环,将一个个匿名函数function () { return i }整体作为元素添加到数组result内,但是这个函数并没有被调用,最终for循环依次执行直到i = 10。匿名函数引用的i就是外部变量for循环中的i,所以之后数组内的函数的i都是10
2)调用函数foo后,变量foo1即数组result。数组里面元素依次是10个function () { return i }。var res1 = foo1[2],开始执行数组第三项function () { return i },此时的i = 10,所以,返回值就是10,包括其他数组项也都是10。

2、由于闭包不立即执行,调用时才执行,所以利用这个特性将其改为立即执行,则可以在函数循环中取得同一变量不同值

function foo () {
	var result = new Array()
	for (var i = 0; i < 10; i++) {
		result[i] = (function (num) {//用参数num绑定i当前值
			return function () {//闭包函数
				return num//函数执行i次,返回的num=i
			}
		})(i)//立即执行函数,i值从0到10依次传递
	}
	return result
}
var foo2 = foo()

此时foo执行,其内部函数也在循环中立即执行,每次不同的值添加到数组result中,因此返回的result数组赋值的foo2中值也是0-10

var res2 = foo2[3]
console.log(res2())//3

3、利用闭包函数实现函数复用

function foo (x) {
	return function (y) {//闭包函数
		return x - y
	}
}
const foo1 = foo(5)
const foo2 = foo(10)

返回函数赋值给foo1、foo2,此处传参5、10为x

console.log(foo1(2))//3
console.log(foo2(2))//8

执行闭包函数,传参2为y

4、利用闭包实现计数器

function counter () {
	var i = 0
	return function () {
		return i+=1
	}
}
var counts = counter()
console.log(counts())//1
console.log(counts())//2
console.log(counts())//3

闭包引用一直不销毁,则其引用的变量 i 也一直存在

console.log(counter()())//1
console.log(counter()())//1
console.log(counter()())//1

但每次初始化counter函数,则内部的变量i和闭包函数也都重新创建

四、this
this指向的是运行函数所处的执行环境

var name = 'window';
function foo () {
	var name = 'foo'
	return function () {
		return this.name
	}
}
var f1 = foo()
console.log(f1())//window

匿名函数内this指向全局

var name = 'window'
var obj = {
	name: 'obj',
	getName: function () {
		var that = this
		return function () {
			return that.name
		}
	}
}
console.log(obj.getName()())//obj

把函数作用域中的this保存在一个变量,使用闭包函数访问这个变量

五、内存泄漏
如果闭包函数的作用域链中包括了html元素,则此元素无法被销毁,需要手动置为null

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值