JS基础核心之闭包

2020-08-21  本文已影响0人  付出的前端路

1. 闭包是什么?

function A () { // chrome认为的闭包是A函数
  var num = 1
  return function B () {
    console.log(num)
  }
}
var C = A ()
// 函数A中的变量num被全局函数C引用着,以至于不会被垃圾回收机制回收
C() // 1 // 大多数书籍理解的闭包是C函数

在A函数中嵌套B函数,B函数访问A函数中的变量。将A函数复制给C函数并执行。

那么在大多数的理解中,包括许多著名的书籍,文章里都以函数C的名字代指这里生成的闭包。而在chrome中,则以执行上下文A的函数名代指闭包。

而我的理解是:闭包更准确的说是一项技术或者一个特性:只要运用具备阻止垃圾回收机制回收和突破作用域链限制的技术,就是闭包。像是《JavaScript权威指南》打的比方,像是把变量包裹了起来,形象的称为“闭包”。

如果非要指明哪个函数是闭包的话,我愿意将A函数称为定义闭包的函数,C函数为执行闭包的函数。

2 生成闭包的条件是什么?

function foo() { // 定义闭包
    var a = 10;
    function baz() {
      console.log(a);
    }
    baz(); // 被确认创建闭包
}

baz();

a. 在函数内部创建新的函数;

b. 新的函数在执行时,访问了函数的变量对象。

c. 闭包是在函数被调用执行的时候才被确认创建的。

一句话总结:==函数中闭包判定的准则,即执行时是否在内部定义的函数中访问了上层作用域的变量。==

3. 闭包的作用是什么?

闭包,阻止垃圾回收机制。

闭包,突破作用域链接。

4 闭包的应用

模块模式

《你不知道的JS中》的示例:

function coolModule () {
  // 私有变量和函数
  var something = 'cool';
  var another = [1, 2, 3]
  function doSomething () {
    console.log(something)
  }
  function doAnother () {
    console.log(another.join('!'))
  }
  // 公开方法
  return {
    doSomething,
    doAnother
  }
})
var foo = coolModule ()
foo.doSomething() // cool
foo.doAnother() // 1!2!3

模块模式需要具备两个必要条件:

1.必须有外部的封闭函数,该函数必须至少被调用一次(每次调用都会创建一个新的模块实例)。

2.封闭函数必须返回至少一个内部函数,这样内部函数才能在私有作用域中形成闭包,并且可以访问或者修改私有的状态。

什么时候使用模块模式?

如果必须创建一个对象并一某些数据对其进行初始化,同时还要公开一些能够访问这些私有数据的方法,那么就可以使用模块模式。

哪些地方有用到模块模式?

最典型的就是JQuery库,jQuery和$标识符就是JQuery模块的公共API,但它们本身都是函数(由于函数也是对象,它们本身也可以拥有属性)

以后单独拿一个章节,来具体讲讲现在的模块化和未来的模块化机制。

柯里化

具体的内容在函数的柯里化的章节中详细分析。

戳此传送门

面试题

  1. 防抖和节流
    戳此传送门
  1. 定时器
for (var i = 1; i <= 5; i++) {
  setTimeout(function timer() {
    console.log(i); // 5次6
  }, i * 1000);
}

输出6的原因是:被封闭在一个共享的全局作用域中,实际上只有一个i。

for (var i = 1; i <= 5; i++) {
  (function (j) {
    setTimeout(function timer() {
      console.log(j); // 依次输出1至5
    }, i * 1000);
  })(i)
}

依次输出1-5的原因是:在迭代内部使用IIFE(立即表达函数)为每个迭代生成一个新的作用域,将外部变量的值传递进去并被引用(阻止垃圾回收机制回收),使得每个回调函数都能访问到正确值的变量。

  1. jn-toast组件认识闭包

戳此传送门

上一篇下一篇

猜你喜欢

热点阅读