front-end-interview-questions icon indicating copy to clipboard operation
front-end-interview-questions copied to clipboard

【JavaScript】谈谈作用域与作用域链的理解,如何理解?

Open yayxs opened this issue 3 years ago • 0 comments


title: 谈谈作用域与作用域链的理解,如何理解?

面试的时候,面试官会问JS中的作用域是什么 要知道作用域是什么 我们需要先了解几个简单的概念

编译原理

编译阶段

编译原理 执行的过程一般会有三个步骤

  • var name 编译时处理
  • name = yayxs 运行时处理

也就是 JS 是在一边进行编译 一边进行执行(所有的代码片段在执行之前会被编译 同时编译 的过程十分短暂)

变量查找

其次的话是引擎 查询变量的两种方式

  • 一个是LHS 查询
  • 一个是RHS 查询

也就是说当变量出现在赋值操作的左侧进行 LHS ;当出现在右侧时进行RHS 一上来就搞这些乱起八遭的英文缩写,啥意思

console.log(a)

以上的代码就是想得到 a 的值,那就是——RHS

a = 123

以上的代码给a 赋值,那就是——LHS

那么说完查询的方式,跟作用域有什么用?其中从某种方式上来理解作用域便是查找变量的一套规范化的规则

那如果我查找的引用无法在当前的作用域内完成怎么办,比如说

function foo(a) {
  console.log(a + b) // b取值,想得到b的值,那就是RHS 那么引用的查找在当前的 foo无法完成
}

var b = 123
foo(456)

如果使用了当前作用域中不存在的变量 引擎就需要按照作用域链在其他作用域中查找该变量

词法作用域

下图展示的一个可视化的作用链(有点像一栋大楼) foo 下面是一段 JS 代码,虽然是 foo 中调用的 bar 但是 bar 函数的外部引用确实全局上下文。因为在 JS 执行过程中

function bar() {
  console.log(myName)
}
function foo() {
  var myName = '--yayxs--'
  bar()
}
var myName = '--vast--'
foo()

整个的一块就像是一栋大楼,然后不停的勇敢的向上走,我们如上提及的那栋大楼便是词法作用域

词法作用域就是指作用域由代码声明的位置决定的,所以词法作用域是静态的作用域通过它能够预测代码在执行中如何查找标识符

  • 一种是词法作用域
  • 一种是动态作用域

那我们重点聊的是词法 ,下面来看一段代码 foo

我们还不得不谈 函数作用域 以及 块作用域

  • 生命每个函数都会自身创建一个笑脸

    对于内部的实现我们是可以隐藏的,比如

    function doSomething(){
      ....balabala
    }
    

谁也不知道函数里干了啥,巴拉巴拉

当我们这样写的时候

;(function foo() {
  console.log(`I LOVE MEINV`)
})()

我们社区给这种操作起了个骚气的名字IIFE 即为 立即执行表达式,在我们实际开发的时候是十分常见的

  • 还有就是块作用域

    那么什么情况下会形成块作用域

    • with 用 with 从对象中创建的作用域仅在 with 声明中而非外部 对 with 语句来说,会向作用域链前端添加指定的对象
    • try catch

    其中catch 分句会创建一个块作用域 则会创建一个新的变量对象,这个变量对象会包含要抛出的错误对象的声明。

    try {
      console.log(a)
    } catch (error) {
      console.log(error)
    }
    console.log(error) // ReferenceError: error is not defined
    
    • let

      为其声明的变量隐式的劫持了所在的块作用域

    • const

      const 同样可以创建一个块级作用域

作用域

在程序中定义变量的区域 决定了 变量的声明周期

  • 变量和函数可访问的范围
  • 作用域控制着变量和函数的可见性和声明规则

在 ES6 之前只有两种

  • 函数作用域 : 函数内部定义的变量或者函数 只能在函数的内部被访问 函数执行结束后 函数内部定义的变量就被销毁

  • 全局作用域:代码在任何地方都能访问 声明周期伴随着页面的声明周期

ES6 出现

  • 块级作用域
//if 块
if(1){}

//while 块
while(1){}

// 函数块
function foo(){

//for 循环块
for(let i = 0; i<100; i++){}

// 单独一个块
{}

作用域链

首先了解 执行上下文 上下文中的代码在执行的时候,会创建变量对象的一个作用域链(scope chain)。这个作用域链决定了各级上下文中的代码在访问变量和函数时的顺序。 理解作用域链是理解闭包的基础 并且闭包是无处不在的,同时 作用域和作用域链是所有编程语言的基础学透一门语言,作用域和作用域链一定是绕不开的。 这也就意味着如果在 bar 函数或者 foo 函数中使用了外部变量,那么 JavaScript 引擎会去全局执行上下文中查找。我们把这个查找的链条就称为作用域链。

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

作用域与作用域链-第 2 页

yayxs avatar Feb 24 '21 01:02 yayxs