8000 作用域与闭包 - 闭包的实现原理和作用 · Issue #28 · logan70/Blog · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

作用域与闭包 - 闭包的实现原理和作用 #28

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
logan70 opened this issue Nov 28, 2019 · 0 comments
Open

作用域与闭包 - 闭包的实现原理和作用 #28

logan70 opened this issue Nov 28, 2019 · 0 comments

Comments

@logan70
Copy link
Owner
logan70 commented Nov 28, 2019

闭包的实现原理和作用

闭包是什么

MDN对闭包描述如下:

A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment).

闭包是函数创建函数的环境的组合。

标准 可知,JavaScript中函数被创建时都会记录当前词法环境,所以说JavaScript中,每次创建函数,都会生成闭包。

闭包的作用

从技术层面说,静态作用域(词法作用域)是通过闭包实现的。

  1. 函数被创建时会记录所处的词法环境;
  2. 函数被调用时会创建新的词法环境(其中包含一个队外部词法环境的引用),并将外部词法环境引用指向函数创建时所记录的词法环境;
  3. 函数内使用自由变量(不在函数内定义的变量)时,沿着由词法环境组成的作用域链寻找解析。

这样就实现了静态作用域(词法作用域),也就是在编写代码时就能确定变量的解析过程。

我们常说的闭包是什么

我们常说的闭包,也可以说是“有意义”的闭包,具备以下两点特征:

  1. 函数创建时所在的上下文销毁后,该函数仍然存在;
  2. 函数内引用自由变量。

最常见的闭包就是父函数内返回一个函数,返回函数内引用了父函数内变量:

const scope = 'outer'
const genClosure = () => {
  const scope = 'local'
  return () => {
    console.log(scope)
  }
}

const closure = genClosure()
closure()
// <- 'local'

闭包的应用

任何关于闭包的应用总结起来都离不开以下两点:

  • 创建私有变量,隐藏实现细节
  • 延长变量声明周期

函数柯里化和偏函数

柯里化:把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数。

// 柯里化前
const getVolume = (l, w, h) => l * w * h
const volume1 = getVolume(100, 200, 100)
const volume2 = getVolume(100, 200, 300)

// 柯里化后
const getVolume = l => w => h => l * w * h
const getVolumeWithDefaultLW = getVolume(100)(200)
const volume1 = getVolumeWithDefaultLW(100)
const volume2 = getVolumeWithDefaultLW(300)

模块化

用于将内部实现封装,仅对外暴露接口,常见于工具库的开发中。

var counter = (function() {
  var privateCounter = 0
  function changeBy(val) {
    privateCounter += val
  }
  return {
    increment: function() {
      changeBy(1)
    },
    decrement: function() {
      changeBy(-1)
    },
    value: function() {
      return privateCounter
    }
  }
})()

模拟块级作用域

最典型的就是ES6之前for循环中使用定时器延迟打印的问题。

for (var i = 1; i <= 3; i++) {
	setTimeout(function() {
		console.log(i)
	}, i * 1000)
}
// <- 4
// <- 4
// <- 4

使用立即执行函数,将i作为参数传入,可保存变量i的实时值。

for(var i = 1; i <= 3; i++){
  (i => {
    setTimeout(() => {
      console.log(i)
    }, i * 1000)
  })(i)
}
// <- 1
// <- 2
// <- 3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant
0