专栏首页小码农学习笔记一文搞懂 JavaScript 作用域
原创

一文搞懂 JavaScript 作用域

作用域

作用域定义

作用域是指在程序中定义变量的区域,该位置决定了变量的生命周期。通俗地理解,作用域就是变量与函数的可访问范围,即作用域控制着变量和函数的可见性和生命周期。

作用域的分类

JavaScript 一共有三种作用域:

  • 全局作用域
  • 函数作用域
  • 块级作用域

全局作用域和函数作用域

在 ES6 之前,ES 的作用域只有两种:全局作用域和函数作用域。(ES3 开始,try /catch 分句结构和 with 中也具有块作用域,这里不加讨论)

  • 全局作用域 中的对象在代码中的任何地方都能访问,其生命周期伴随着页面的生命周期。
  • 函数作用域 就是在函数内部定义的变量或者函数,并且定义的变量或者函数只能在函数内部被访问。函数执行结束之后,函数内部定义的变量会被销毁。

在 ES6 之前,JavaScript 只支持这两种作用域,相较而言,其他语言则都普遍支持块级作用域。块级作用域就是使用一对大括号包裹的一段代码,比如函数、判断语句、循环语句,甚至单独的一个 {} 都可以被看作是一个块级作用域。

简单来讲,如果一种语言支持块级作用域,那么其代码块内部定义的变量在代码块外部是访问不到的,并且等该代码块中的代码执行完成之后,代码块中定义的变量会被销毁。

遗憾的是,JavaScript 在 ES6 之前是不支持块级作用域的。没有块级作用域,对作者当时设计 JavaScript 来说会比较简单快速,但这也直接导致了「变量提升」的问题。

块级作用域

为了解决变量提升带来的一系列问题,ES6 引入了 letconst 关键字,从而使 JavaScript 也能像其他语言一样拥有了块级作用域

需要注意的是,只有 letconst + 大括号({})才能构成块级作用域,否则单纯的大括号({})只是用作代码分割,让代码阅读起来更简单轻快一点,纯粹代码维护上的需求。

通过 let 或者 const 声明的变量会在进入块级作用域的时候被创建,但是在该变量没有赋值之前,引用该变量 JavaScript 引擎会抛出错误,这就是「暂时性死区」,对于暂时性死区的问题,本章节不展开讨论。

词法作用域

词法作用域就是指作用域是由代码中函数声明的位置来决定的,所以词法作用域是静态的作用域,通过它就能够预测代码在执行过程中如何查找标识符。(标识符:在 JS 中所有可以由我们自主命名的都可以称为是标识符,例如:变量名、函数名、属性名都属于标识符)

—— 出自《你不知道的JavaScript(上)》

作用域链

作用域链也称词法作用域链,顾名思义,它跟词法作用域有关。

作用域链本质上就是查找变量的链条(确定变量来自于哪里,变量是否可以访问,或者说,确定一个变量来自于哪个作用域)。

简单来说,作用域链可以用以下几句话来概括:

  • Step1 查看当前作用域,如果当前作用域声明了这个变量,就确定结果;
  • Step2 查找当前作用域的上级作用域,也就是当前函数的上级函数,看看上级函数中有没有声明;
  • Step3 再查找上级函数的上级函数,直到全局作用域为止;
  • Step4 如果全局作用域中也没有,我们就认为这个变量未声明(抛出异常:xxx is not defined)。

重点:词法作用域是代码阶段就决定好的,和函数是怎么调用的没有关系

举个例子:

function innerFunction() {
    console.log(myName);
}
function outerFunction() {
    var myName = "函数作用域";
    innerFunction();
}

var myName = "全局作用域";
outerFunction();

从代码中可以看出,全局执行上下文和 outerFunction 函数的执行上下文中都包含变量 myName,那 innerFunction 函数里面 myName 的值到底该选择哪个?

根据上面提到的查找顺序,查找方式如下:

  • Step1 查看当前作用域,innerFunction 函数里面不存在变量 myName
  • Step2 innerFunction 函数中使用了外部变量,向上级查找。

重点来了,由于 innerFunction 函数里面不存在变量 myName ,此时 JavaScript 引擎会去全局执行上下文中查找,而不是它的调用方 outerFunction 函数的执行上下文。这是因为在 JavaScript 执行过程中,其作用域链是由词法作用域决定的,而词法作用域是代码阶段就决定好的,和函数是怎么调用的没有关系

既然如此,根据词法作用域,outerFunctioninnerFunction 的上级作用域都是全局作用域,所以如果 outerFunction 或者 innerFunction 函数使用了一个它们没有定义的变量,那么它们会到全局作用域去查找。


文章持续更新,本文 GitHub 前端修炼小册 已经收录,欢迎 Star。如对文章内容有不同见解,欢迎留言交流。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • JavaScript进阶教程(5)-一文让你搞懂作用域链和闭包

    在JS中变量可以分为局部变量和全局变量,对于变量不熟悉的可以看一下我这篇文章:搞懂JavaScript全局变量与局部变量,看这篇文章就够了 作用域就是变量的使用...

    AlbertYang
  • 「译」一个案例搞懂 Vue.js 的作用域插槽

    作用域插槽是 Vue.js 中一个很有用的特性,可以显著提高组件的通用性和可复用性。问题在于,它实在不太好理解。尝试搞清楚父子作用域之间错综复杂的关系,其痛苦程...

    Chor
  • 一文带你搞懂JavaScript的Generator函数

    而 Generator 可以按需一个接一个地返回(“yield”)多个值。它们可与 iterable 完美配合使用,从而可以轻松地创建数据流。

    前端进阶者
  • 一文带你彻底搞懂JavaScript原型链

    Brendan Eich(布兰登·艾奇) 作为JavaScript的作者曾说过 “它是C语言和Self语言一夜情的产物。”

    童欧巴
  • JavaScript-作用域、块级作用域、上下文、执行上下文、作用域链

    (2)实际上,JavaScript默认有一个全局对象window,全局作用域的变量实际上被绑定到window的一个属性。

    WEBING
  • 一文搞懂spring工作的流程

    三哥
  • 一篇文章带你了解JavaScript作用域

    在JavaScript中,对象和函数也是变量。在JavaScript中,作用域是你可以访问的变量、对象和函数的集合。

    前端进阶者
  • JavaScript作用域

    秋白
  • javascript作用域

    javascript的作用域一直以来是前端开发中比较难理解的知识点,对于javascript的作用域主要记住几句话.

    Wyc
  • JavaScript 作用域

    在 HTML 中, 全局变量是 window 对象: 所有数据变量都属于 window 对象。

    陈不成i
  • 一文教你搞懂 Go 中栈操作

    多任务操作系统中的每个进程都在自己的内存沙盒中运行。在32位模式下,它总是4GB内存地址空间,内存分配是分配虚拟内存给进程,当进程真正访问某一虚拟内存地址时,操...

    luozhiyun
  • 一文搞懂文件操作与异常模块

    大家好!我是云朵君,今天给大家带来一篇Python文件操作与异常处理,这两个部分往往是初学者入门时容易忽略的部分。大家重点的精力都放在如何写出高大上的算法,如何...

    数据STUDIO
  • 一文搞懂Spring-AMQP

    12//设置消息发送ack,默认noneconnectionFactory.setPublisherConfirmType(CachingConnection...

    爱撒谎的男孩
  • 一文搞懂 Flink Timer

    顾名思义就是 Flink 内部的定时器,与 key 和 timestamp 相关,相同的 key 和 timestamp 只有一个与之对应的 timer。tim...

    shengjk1
  • 每个JavaScript工程师都应懂的33个概念

    这个项目是为了帮助开发者掌握 JavaScript 概念而创立的。它不是必备,但在未来学习(JavaScript)中,可以作为一篇指南。

    Fundebug
  • 每个JavaScript工程师都应懂的33个概念

    这个项目是为了帮助开发者掌握 JavaScript 概念而创立的。它不是必备,但在未来学习(JavaScript)中,可以作为一篇指南。

    Fundebug
  • 一文彻底搞懂 HTTPS 的工作原理!

    当你打开浏览器,访问某个网站,如果网址旁有个小锁,代表访问的网址是安全的,反之不安全。当我们没有看到那个小锁的小图标的时候,需要提高警惕,不要随意输入个人重要的...

    杰哥的IT之旅
  • 一网打尽 JavaScript 的作用域[每日前端夜话0x49]

    JavaScript 的作用域包括:模块作用域,函数作用域,块作用域,词法作用域和全局作用域。

    疯狂的技术宅
  • 理解javascript作用域和作用域链

    作用域就是变量和函数的可访问范围,控制着变量和函数的可见性与生命周期,在JavaScript中变量的作用域有全局作用域和局部作用域。

    令仔很忙

扫码关注云+社区

领取腾讯云代金券