作用域和闭包
前言
首先,问一下自己:
你知道javascript的词法作用域是基于编译器语义而不是解析器的吗?
你能理解词法作用域和作为值得函数这两者得直接结果之一就是闭包吗?
假如你都不知道,看完这个,应该就略知一二(精通好吧)了。
作用域
作用域就是负责收集并维护由所有声明的变量组成的一系列查询,并实施的一套非常严格的规则,确定当前执行的代码对这些标识符的访问权限。这个规则就是作用域。
在理解上面那么高深的东西之前先科普一下编译器的点儿知识,LHS查询和RHS查询。
LHS:找到变量的容器本身,从而对其赋值
RHS:取到某某的值
所以来看以下例子:
var a = 2;
console.log(a);
var a 就是将变量a收集起来以待查询
a = 2 是一个LHS引用,只想找到a给它赋值
console.log(a) 是一个RHS引用,只想找到a的值
LHS和RHS查询都会在当前执行作用域中开始,如果有需要(在当前作用域未找到),就会向上级作用域继续查找目标标识符,最后到达全局作用域,无论找到或没找到都会停止
如果RHS查询没找到会抛出ReferenceError异常,LHS查询没找到会导致创建一个全局变量(非严格模式),严格模式下也会抛出异常。
测验1:
function foo(a) {
var b = a;
return a + b;
}
var c = foo(a)
找出所有的LHS查询
找出所有的RHS查询
测验2:
function foo(a) {
console.log(a + b)
b = a
}
foo(2)
会报错吗,为什么?
闭包
对于闭包的理解,我之前就是认为在一个函数中调用了另一个函数就叫做闭包。
但是当我在《你不知道的JavaScript》中看到,无论通过何种手段将内部函数传递到所在词法作用域以外,它都会持有对原始定义作用域的引用,无论在何处执行这个函数都会使用闭包。
也就是说,当你将一个变量放到它的词法作用域以外的地方使用,就算是执行了闭包,也就会一直保留变量的词法作用域。
首先,什么是词法作用域呢?
前面我们了解了什么是作用域,而作用域又分为两种,一种是词法作用域,一种是动态作用域。
词法作用域就是定义在词法阶段的作用域,也就是说由你在写代码时将变量和块作用域写在哪里决定的。
动态作用域就是让作用域作为一个在运行时才被动态确定的形式。
行百里者半九十