深入理解闭包二(进阶必备知识)

249 阅读2分钟

这是我参与8月更文挑战的第8天,活动详情查看:8月更文挑战

LHS、RHS

TIP 👉 LHS、RHS,是引擎在执行代码的时候,查询变量的两种方式。其中L、R,分别意味着Left、Right,这个“左”、“右”,是相对于赋值操作来说的。当变量出现在赋值操作的左侧时,执行的就是LHS操作,右侧则执行RHS操作

name = 'qinliang'

在这个例子里,name变量出现在赋值操作的左侧,它就属于LHSLHS意味着变量赋值或写入内存,它强调的是一个写入的动作,所以LHS查询查的是这个变量对应的内存空间在哪。

let myName = name
console.log(name)

在这个例子中,第一行有赋值操作,但是name在操作的右侧,所以是RHS;第二行没有赋值操作,name就可以理解为没有出现在赋值操作的左侧,这种情况下我们也认为name的查询是RHS。RHS意味着变量查找货从内存中读取,它强调的是读这个动作,查询的是变量的内容。

词法作用域和动态作用域

JS的作用域遵循的就是词法作用域模型。当面试官抛出“词法作用域”这个的时候,它指的就是你最熟悉的JS作用域。

作用域其实有两种主要的工作模型:

  1. 词法作用域:静态作用域。

  2. 动态作用域:像Bash脚本等

var name = 'qinglian'

function showName() {
    console.log(name)
}

function changeName() {
    var name = 'BigBear'
    showName()
}

changeName(); // qinglian
  • 在showName函数的函数作用域内查找是否有局部变量name
  • 发现没找到,于是根据书写的位置,查找上层作用域也就是全局作用域,找到了name的值是qinglian,所以结果就是qinglian

此时它的作用域关系如下:

image.png

作用域链如下:

image.png

这里我们作用域的划分,是在书写的过程中(例子中也就是在函数定义的时候,块级作用域同理是在代码块定义的时候),根据你把它写在哪个位置来决定的。像这样划分出来的作用域,遵循的就是词法作用域模型。

那什么是动态作用域呢?

  • 在showName函数的函数作用域内查找是否有局部变量name
  • 发现没找到,于是沿着函数调用栈、在调用了showName的地方继续找name。刚好,changeName里又一个name,于是这个name就会被引用到showName里去。

它的作用链关系如下:

image.png

如果是动态作用域,那么这段代码运行的结果就是‘BigBear’

修改词法作用域

  1. with

  2. eval

注意⚠️:开发过程中不要用with和eval写代码。