《你不知道的JS(上卷)》作用域闭包

Posted lalal

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《你不知道的JS(上卷)》作用域闭包相关的知识,希望对你有一定的参考价值。

五、作用域闭包:

? 闭包不是神奇的魔法,它只是遵循我们前几章一直介绍的 词法作用域书写代码的自然结果。

? 闭包是由函数以及声明该函数的词法环境组合而成的。该环境包含了这个闭包创建时作用域内的任何局部变量。

一)、回调函数与闭包:

  • 回调函数,将一个函数的引用作为参数传递给另一个函数。
function wait(meesage) {
	setTimeout(function timer() {
		console.log(meesage);
	}, 1000);
}
wait("Hello, closure!")

? 无论何时何地,如果将函数(访问他们各自的词法作用域)当作第一级的值类型并到处传递,就可以看到闭包的存在。在定时器、事件监听器、Ajax请求、跨窗口通信等异步或同步任务中,只要使用了回调函数,实际上就是在使用闭包。

二)、循环与闭包:

// 使用var
for (var i = 1; i <= 5; i++) {
	setTimeout(function timer() {
		console.log(i);
	}, i * 1000)
} // 6 6 6 6 6 

// 使用let
for (let i = 1; i <= 5; i++) {
	setTimeout(function timer() {
		console.log(i);
	}, i * 1000)
} // 1 2 3 4 5

? 比较上面两段代码与输出结果。发现使用var在循环中声明变量不能达到我们想要的效果。这是因为尽管每次循环都定义了一个新的函数,但是对于这些函数,是共享同一个作用域的,因此i也是相同的。而使用let,会在每次迭代时都创建一个新的作用域。并且使用let会让i这个变量在每次迭代都会声明,且会使用上一个迭代结束时的值来初始化这个变量。

三)、模块模式:

? 在许多面向对象语言(如Java)中,都支持将方法声明为私有,即只能被同一个类中的方法调用。在javascript中并没有这种原生支持。我们可以使用闭包来模拟私有方法,这种方式也被称作 模块模式

? 这种方式不仅有利于限制对代码的访问:还提供了管理全局命名空间的强大能力,避免非核心的方法弄乱代码的公共接口部分。

var foo = (function CoolModule() {
  var something = "cool";
  var another = [1, 2, 3];

  function doSomething() {
    console.log(something);
  }

  function doAnother() {
    console.log(another.join("!"));
  }

  return {
    doSomething: doSomething,
    doAnother: doAnother
  }

})();

foo.doSomething(); // cool
foo.doAnother(); // 1!2!3

ES6中的模块机制:

? ES6中为模块增加了一级语法支持。但通过模块系统进行加载时,ES
6会将文件当作独立的模块来处理。每个模块都可以导入其他模块或特定的API成员,同样也可以到处自己的API成员。

  • import可以将一个模块中的一个或多个API导入到当前作用域中,并分别绑定在一个变量上。
  • module会将整个模块的API导入并绑定到一个变量上。
  • export会将当前模块的一个标识符(变量、函数)导出为公共API。

四)、小结:

  • 闭包虽然随处可见,但是不要滥用。使用闭包在处理速度和内存消耗方面对脚本性能具有负面影响。
  • 理解闭包的关键还是前几章讲述的词法作用域,因此不能跳过前几章!

以上是关于《你不知道的JS(上卷)》作用域闭包的主要内容,如果未能解决你的问题,请参考以下文章

《你不知道的 JavaScript 上卷》 学习笔记

你不知道的JavaScript-上卷の读书笔记

你不知道的JavaScript(上卷)

JS闭包的理解

《你不知道的JavaScript》整理——作用域提升与闭包

你不知道的Javascript(上卷)读书笔记之一 ---- 作用域