理解闭包

·  阅读 130

这是我参与11月更文挑战的第27天,活动详情查看:2021最后一次更文挑战

闭包的本质

一个普通的函数function,如果它可以访问外层作用域的自由变量,那么这个函数就是一个闭包

  • 闭包中内部函数为什么可以访问到外部函数中的变量?

函数在执行的时候会放到一个执行栈上,当函数执行完毕之后会从执行栈上移除,但是堆上的作用域成员因为外部引用不能释放,因此内部函数依然可以访问外部函数的成员。

  • 什么函数是闭包?
  1. 从某种角度来说,所有的函数都是闭包。因为他们都可以访问全局作用域
  2. JavaScript中一个函数如果访问了外层作用域中的变量,那么它就是一个闭包
  • 为什么会产生闭包?

内部函数在外界有引用,内部函数有一个作用域变量[[scope]] 包含了当前函数的AO对象和父级函数的AO对象。所以导致父级AO对象无法被垃圾回收,所以内部函数执行的时候仍然可以访问到外部函数中的变量。

虽然我们引用了 外部函数的AO对象,但是v8引擎会帮我们做优化, 优化这个AO对象,会让这个对象中我们用不到的属性删除掉。

  • 下面代码中产生的闭包变量是什么?
function foo () {
  const age = 18
  const arr = new Array(100000).fill(1)
  return function () {
    console.log(age);
  }
}
foo()()
复制代码

foo函数的AO对象包含了age,arr,但是在内部函数中,我们只使用到了age,那么arr这个数据在foo函数执行完毕的时候被垃圾回收到吗?答案是会的,上述代码中闭包变量只有age。 v8引擎会帮我们让foo的AO对象只留下我们内部函数中使用到的age。可以在chrom调试的closure中看到。

闭包案例

实现一个once函数,即此函数只能执行一次。

// 实现once
function once(fn) {
	let done = false
	return function () {
		if (!done) {
			done = true
			fn.apply(this, arguments)
		}
	}
}
function pay(num) {
    console.log('付款: ' + num)
}
const oncePay = once(pay)
oncePay(2)
oncePay(5)
oncePay(4)
oncePay(3)
复制代码

上述代码只会执行一次。

分类:
前端
标签: