[js基础知识01]理解JavaScript的词法作用域

258 阅读3分钟

js的作用域

此文章参考《你不知道的JavaScript》

这篇文章会聚焦以下几个问题:

  1. 什么是作用域
  2. 变量查找规则
  3. js中的作用域

什么是作用域

对与任何一门编程语言来说。最基本的功能就是存放变量的值,之后访问与修改这个值。这个值放在哪里,访问这个值的规则是什么?这一系列的操作都是作用域在实现。

也就是说js需要一套合理的规则来规定变量的存放,然后之后很方便的找到这个变量,这套规则就是作用域

(变量查找规则)LHF && RHF

在js中查找总归来说有两种方式,一个是左查找。一个是右查找。

何为“左”,何为“右”

左右是相对的,需要找到一个参考点。即:等号的左边右边。得出结论: 变量得左边即为左查找,变量得右边即为有查找。看似正确, 却不全面。参考一下例子:

console.log(a) 

test(2, 3)

functiong test(a, b)

以上代码没有等号作为参考,又是什么查找了?

分析 var a = b 本质

可以理解为:变量b得值赋值给变量a。即:

  1. 右查找: 查找变量的值
  2. 左查找: 查找这个变量

练习

function foo(a) {
    var b = a
    return a + b
}

var c = foo(2)

副作用(非严格模式下)

副作用的意思:对一个变量进行左右查找,沿着作用域一层一层的查找上去,到最底层都没有找到。会发生什么。 此处的副作用也可以理解为异常。

  1. 左查找副作用例子
function foo() {
 a = 10 // 对a进行左查找
}
foo()
console.log(a) 

运行结果输出10. 得出结论:当对一个变量进行左查找的时候,到最顶层都没有找到。则程序会贴心的给你在全局作用域创建一个变量。这就是我们常说的全局变量泄露

  1. 右查找副作用例子
console.log(a)

抛出异常:ReferenceError:a is not defined.

词法作用域

作用域有两种工作模式:

  1. 词法作用域
  2. 动态作用域

词法作用域(简单介绍)

大部分编程语言来说,在执行代码之前要经过三个阶段,这三个阶段叫做“编译”。

  1. 分词/词法分析: 讲程序字符串分解成有意义的代码段:var a = 10 分解为: var, a, =, 10。 这些代码段叫做词法单元。
  2. 解析/语法分析:讲词法单元,分析成为抽象语法树(AST)
  3. 代码生成: 讲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不是动态作用域。

小结

  1. 作用域是变量查找的一套规则
  2. 左查找是查找这个变量,右查找是查找这个变量的值
  3. 如果变量找不到。左查找会造成全局变量泄露,右查抛出异常
  4. 在js中作用域是词法作用域