javascript 的作用域
- 在 javascript 中, 没有块级的作用域 (反人类), 所以为了避免误解, 最好不要在块作用域内声明变量
1 | var i = 10; |
- 除了全局作用域, 只有函数才可以创建作用域
- 作用域有上下级关系, 最大的目的就是隔离变量, 不同作用域下同名变量也不会冲突
1 | var a = 10; //window.a = 10; 全局作用域 |
javascript 的作用域和执行上下文环境
- 作用域只是一个“地盘”,一个抽象的概念。
- 如果要查找一个作用域下某个变量的值,就需要找到这个作用域对应的执行上下文环境,再在其中寻找变量的值。
- 作用域中变量的值是在执行过程中产生的确定的,而作用域却是在函数创建时就确定了。
- 同一个作用域下,不同的调用会产生不同的执行上下文环境,继而产生不同的变量的值。
作用域和上下文环境绝对不是一回事儿
- 作用域:
首先,它很抽象。另外除了全局作用域,只有函数才能创建作用域。创建一个函数就创建了一个作用域,无论你调用不调用,函数只要创建了,它就有独立的作用域,就有自己的一个“地盘”。
- 上下文环境:
可以理解为一个看不见摸不着的对象(有若干个属性),虽然看不见摸不着,但确实实实在在存在的,因为所有的变量都在里面存储着,要不然咱们定义的变量在哪里存?
另外,对于函数来说,上下文环境是在调用时创建的,这个很好理解。拿参数做例子,你不调用函数,我哪儿知道你要给我传什么参数?
- 两者之间的关系:
一个作用域下可能包含若干个上下文环境。有可能从来没有过上下文环境(函数从来就没有被调用过);有可能有过,现在函数被调用完毕后,上下文环境被销毁了;有可能同时存在一个或多个(闭包)。
1 | var x = 100; |
上面代码一个fn作用域下同时存在两个上下文环境。可以理解作用域是静态的组织结构,而上下文环境是动态的调用。
自由变量依赖静态作用域
- 在 A作用域中使用的变量 x, 却没有在 A作用域中声明(即在其他作用域中声明的), 那么对于 A作用域来说, x 就是一个自由变量.
1 | var x = 10; |
那么去哪里取自由变量的值? 要到 创建 包含自由变量 函数 的那个 作用域 中取值——是“创建”,而不是“调用”. 一定要切记其实这就是所谓的“静态作用域”。
那么在执行 fn 的时候, x 取值去哪里取呢? 答案是要到创建fn函数的那个作用域中取——>无论fn函数将在哪里调用。(anywhere call, only find on create)
如果静态作用域找不到怎么办? 此时就需要一级一级跨作用域一直找到全局作用域
1 | var a = 10; |
来看一道题:
1 | var x = 10; |
闭包其实就是上下文环境不销毁
闭包一般只有两种情况——函数作为返回值,函数作为参数传递。
1 | function fn(){ |
- 全局上下文环境准备, global —> f1 = undefined, max = undefined
- 执行到 var f1 = fn(); 进入fn()执行上下文环境. fn —> max = 10
- fn() 函数返回, 本来要销毁上下文的max, 但是 bar 函数却引用了这个max, 因此这个max不能被销毁,销毁了bar函数中的max就找不到值了。所以fn()上下文环境保留. fn —> max = 10
- var max = 100; global —> f1 = fn(), max = 100
- f1(15) 进入fn执行上下文环境, max 是10, x 是15, 输出15
- 执行完毕进入全局上下文环境