Fork me on GitHub

你不知道的JavaScript(作用域与闭包)

  • RHS查询,LHS查询

  • 变量的赋值过程

  • RHS查询与简单地查找某个变量的值没有什么差别,但是LHS查询则是试图找到变量的容器本身,从而可以对他赋值

  • LHS——赋值的目标是谁?RHS——谁是赋值操作的源头?
    如果查找的目的是对变量进行赋值,那么就会使用LHS 查询;如果目的是获取变量的值,就会使用RHS 查询。

  • 作用域查找会在第一个匹配的标识符时停止

  • 欺骗词法:
    1、使用eval,遮蔽了外部(全局)作用域中的同名变量

使用eval

在严格模式的程序中,eval(…)在运行时候有其自己的词法作用域,意味着其中的声明无法修改所在的作用域。

2、with

with

  • 作用域气泡的概念

  • 从所写的代码中挑选出一段任意的片段,然后用函数声明对它进行包装,实际上就是把这些代码“隐藏起来”

  • 隐藏内部实现

  • 函数表达式和函数声明

  • 推不推荐使用arguments.callee?

  • 行内函数表达式非常强大而且有用

  • 立即执行函数(IIFE Immediately Invoked Function Expression)

    1
    (function foo(){...}())  (function foo(){...})()

IIFE 一个很普遍的进阶用法就是把它们当做函数调用并传参数过去

IIFE还有一种用途就是倒置代码的运行顺序,将需要运行的函数放在第二位,在IIFE执行之后当做参数传递进去

IIFE

  • try…catch…中的catch分句会创建一个块级作用域,其中声明的变量仅仅在catch的内部使用

  • 引擎会在解释JavaScript代码之前首先对其进行编译,编译阶段中的一个部分工作就是找到所有的声明,并用合适的作用域将它们关联起来

包含变量和函数在内的所有声明都会在任何代码被执行前首先被处理

声明和赋值

报错

foo这个时候是undefined,但是对其进行函数调用的话会导致非法操作,因此抛出TypeError异常

  • 函数优先

  • 当函数可以记住并访问当前所在的词法作用域时候,就产生了闭包,即使函数是在当前词法作用域之外执行的

  • 原本应该在函数执行结束后进行垃圾回收,但是bar()所声明的位置决定了它拥有涵盖foo()内部作用域的闭包,使得该作用域一直存活着,从而提供bar()在之后任何时间进行引用

闭包

  • 所有的函数共享一个i的引用。循环结构让我们误以为背后还有更加复杂的机制在起作用,但实际上是没有的。我们需要更多的闭包作用域,特别是循环的过程中每个迭代都需要有一个闭包作用域

经典例子

而通过IIFE可以声明并立即执行一个函数来创建作用域

1

2

注意两者的区别

  • 本质上这是将一个块转换成一个可以被关闭的作用域

1

2

-------------本文结束感谢您的阅读-------------