js的作用域
此文章参考《你不知道的JavaScript》
这篇文章会聚焦以下几个问题:
- 什么是作用域
- 变量查找规则
- js中的作用域
什么是作用域
对与任何一门编程语言来说。最基本的功能就是存放变量的值,之后访问与修改这个值。这个值放在哪里,访问这个值的规则是什么?这一系列的操作都是作用域在实现。
也就是说js需要一套合理的规则来规定变量的存放,然后之后很方便的找到这个变量,这套规则就是作用域
(变量查找规则)LHF && RHF
在js中查找总归来说有两种方式,一个是左查找。一个是右查找。
何为“左”,何为“右”
左右是相对的,需要找到一个参考点。即:等号的左边右边。得出结论: 变量得左边即为左查找,变量得右边即为有查找。看似正确, 却不全面。参考一下例子:
console.log(a)
test(2, 3)
functiong test(a, b)
以上代码没有等号作为参考,又是什么查找了?
分析 var a = b 本质
可以理解为:变量b得值赋值给变量a。即:
- 右查找: 查找变量的值
- 左查找: 查找这个变量
练习
function foo(a) {
var b = a
return a + b
}
var c = foo(2)
副作用(非严格模式下)
副作用的意思:对一个变量进行左右查找,沿着作用域一层一层的查找上去,到最底层都没有找到。会发生什么。 此处的副作用也可以理解为异常。
- 左查找副作用例子
function foo() {
a = 10 // 对a进行左查找
}
foo()
console.log(a)
运行结果输出10. 得出结论:当对一个变量进行左查找的时候,到最顶层都没有找到。则程序会贴心的给你在全局作用域创建一个变量。这就是我们常说的全局变量泄露
- 右查找副作用例子
console.log(a)
抛出异常:ReferenceError:a is not defined.
词法作用域
作用域有两种工作模式:
- 词法作用域
- 动态作用域
词法作用域(简单介绍)
大部分编程语言来说,在执行代码之前要经过三个阶段,这三个阶段叫做“编译”。
- 分词/词法分析: 讲程序字符串分解成有意义的代码段:var a = 10 分解为: var, a, =, 10。 这些代码段叫做词法单元。
- 解析/语法分析:讲词法单元,分析成为抽象语法树(AST)
- 代码生成: 讲AST转换为可执行代码。
所以词法作用域就是定义在词法分析阶段的作用域。通俗的讲:就是在代码写下得的时候,运行之前。这个变量属于哪个作用域就已经确定了。
var a = 10
function foo() {
console.log(a)
}
foo(a) // foo运行在全局作用域
function baz() {
var a = 100
foo() // foo运行在baz包裹的作用域
}
baz()
都会输出10。因为在代码编写阶段就已经确定好了,foo永远处于全局作用域。foo包裹下的作用域没有a这个变量,然后肯定就会去全局作用域找。
ps:以动态作用域的角度去看这个例子,运行baz这个函数的时候,foo会在baz包裹的作用域下运行。那么baz的上层作用域就是baz,很显然foo会输出100。显然js不是动态作用域。
小结
- 作用域是变量查找的一套规则
- 左查找是查找这个变量,右查找是查找这个变量的值
- 如果变量找不到。左查找会造成全局变量泄露,右查抛出异常
- 在js中作用域是词法作用域