浅谈JavaScript中的作用域|8月更文挑战

640 阅读4分钟

前言

在我们实际编写代码的过程中,总有需要一个独立环境运行代码的需求,我们并不想当前的代码影响了其他的变量,也不想当前的环境内对外部变量依赖过多,导致迁移不方便。为了解决这个问题,作用域诞生了,如果你还没有好好理解作用域的概念,那么今天就带大家一探究竟吧。

作用域

JavaScript 拥有函数作用域:每个函数创建一个新的作用域。

作用域决定了这些变量的可访问性(可见性)。

函数内部定义的变量从函数外部是不可访问的(不可见的)。

这是官方给出的定义。

什么是作用域

作用域指的是您有权访问的变量集合。 JavaScript 拥有函数作用域:每个函数创建一个新的作用域。 作用域决定了这些变量的可访问性(可见性)。 函数内部定义的变量从函数外部是不可访问的(不可见的)。

先不急着理解这句话,我们先看一段及其简单的代码

(function fn() {
    var x = 'x';
    console.log(x); // x
    console.log(y);
})()

描述下这段代码的大致执行流程: 执行函数fn,声明变量x,寻找变量x,自己函数内部找到了x,直接输出,如果没有找到,则会向上进行查找。

函数作用域、全局作用域,把这两个词换入到原来那句话中,第一段代码是在函数作用域中找到x变量,第二段代码是在全局作用域中找到y变量。

通俗的讲,作用域就是查找变量的地方。在某函数中找到该变量,就可以说在该函数作用域中找到了该变量;在全局中找到该变量,就可以说在全局作用域中找到了该变量!

不知道各位同学有没注意到一个细节,我们在查找x变量的时候,先在函数作用域中查找,没有找到,再去全局作用域中查找,有一个往外层查找的过程。我们好像是顺着一条链条从下往上查找变量,这条链条,我们就称之为作用域链。

作用域嵌套

在ES6之前,只有函数作用域和全局作用域,而到了ES6,又了let、const关键字,局部作用域就诞生了。

let x = 'x'; // 全局作用域
function a() { // 函数作用域
    let y = 'y'; // 局部作用域
}

查找变量顺序从里到外,这从里到外的各层作用域就组成了作用域链。

作用域中变量(标识符)的查找规则

首先声明一点,JavaScript是有编译过程的,其实一开始是没有的,这点是在Chrome V8中实现的,目的是为了加快执行效率,我们都知道编译语言的运行性能是优于解释性语言的。

其实编译器是这样工作的,在代码执行之前从上到下的进行编译,当遇到某个用var、let、const声明的变量的时候,先检查在当前作用域下是否存在了该变量。如果存在,则忽略这个声明;如果不存在,则在当前作用域中声明该变量。

词法作用域

简单地说,词法作用域就是定义在词法阶段的作用域,是由写代码时将变量和块作用域写在哪里来决定的,因此当词法分析器处理代码时会保持作用域不变。

我们有的时候也会称它为静态作用域,因为是在写代码的时候就已经决定了,而不是后期动态生成的。

总结

其实理解了JavaScript中的作用域规则,可以有助于我们在日常工作中排查错误,有的时候并不需要通过console、debugger等工具,看下代码,想象一下执行流程,就能大致判断出问题所在了。

最后打波小广告,美团校招社招内推,不限部门,不限岗位,不限投递数量,海量hc,快来快来~