如何彻底理解变量提升,作用域链,闭包?(聊聊js的上下文)

还是先说说文章的由来。

今年其实立了挺多flag的,有源码阅读,有ui框架,有脚手架,有前端监控,还有react源码。完成的怎么样,暂且不提(年底一块总结),至少可以把前端的知识点梳理一遍。

所以这篇文章,来盘一盘js的上下文,彻底理解js一些奇怪的特性。

什么是上下文?

在执行一段js代码之前,会先进行编译,编译的过程中会生成上下文。

首先会生成一个全局上下文。

上下文中包含两块内容,分别是变量环境跟词法环境。

如果代码中有函数,则会生成函数上下文。

保存上下文的是一个栈结构,也就是后进先出。

为什么会变量提升?

在编译阶段,会将变量的声明存在变量环境中。

css 复制代码
    console.log(a)
    console.log(b)
    var a = 1
    function b() {
       var c = 2
    }
    b()

比如这样一段代码,编译阶段上下文情况如下。

然后开始执行代码。

1.输出a为undefined,b为function。

2.将a赋值为1

3.执行函数b,生成b函数的上下文。

此时的上下文情况。

4.将c赋值为2

等函数执行完毕,则会销毁函数上下文。

但是,如果函数中又调用了其他函数,那么就会创建新的函数上下文,压入栈中,也叫调用栈。

栈的大小是有限制的,如果说函数嵌套(一般是递归),有可能造成栈溢出

变量提升,有什么问题?

变量提升其实不太符合常规逻辑。

而且会带来一些问题。

比如变量容易被覆盖。

css 复制代码
    console.log(a)
    console.log(b)
    var a = 1
    function b() {
      console.log(a)
      var a = 2
    }
    b()

还有一个常见的坑,就是本应销毁的变量没有被销毁。

css 复制代码
   function b() {
      for(var a = 0 ;a< 7; a++){}
      console.log(a)
    }
    b()

所以在es6中,引入了let, const来实现块级作用域。(现在基本取代了var)

如何实现块级作用域?

在编译阶段,会将块级变量放到词法环境中。

比如下面这段代码

ini 复制代码
let a = 1
var b = 2
if(true) {
  let c = 3
  let d = 4
  var e = 5
}

此时的上下文如下所示。

并且当我访问变量的时候,查找的顺序,是先从词法环境开始找,再到变量环境。

ps(块级变量的创建会被提升,但是初始化和赋值不会被提升,所以如果在变量前打印是会报错的)

什么是作用域链?

在块级作用域这里说了,变量的查找顺序。

但是,当在自己的作用域范围内找到不到,该怎么办呢?

在上下文中,还有一个属性叫outer,指向需要查找的上下文,也叫做作用域链。

ps(作用域链是在代码中就确定了的,无需在编译中计算)

还是先看一段代码。

javascript 复制代码
function a() {
  console.log(aa)
}

function b() {
  var aa = "2"
  a()
}

var aa = "1"
b()

也就是说,代码写在哪里,outer就指向该上下文。

理解了作用域链,再来看闭包就简单多了。

如何理解闭包?

说闭包之前,先说两句话。

1.函数执行完毕,会销毁函数上下文,变量会被回收

2.内部函数总是可以访问其外部函数中声明的变量(通过作用越链)

这其实就是闭包形成的原因,外面的函数需要销毁,而函数里面的变量被占用,所以就形成了一个内部函数专属的内存包(只有它可以访问),也叫闭包。

javascript 复制代码
function a() {
  let a1 = "a1"
  return function b() {
    console.log(a1)
  }
}

const b = a()
b()

当执行到b = a()的时候,此时的上下文。

因为a函数已经执行完毕,但是变量a1被b函数占用,此时的上下文如下。

ps(闭包的变量回收,果是全局,则等页面销毁,如果是局部,则等函数执行完毕)


到这里,今天的文章就结束了。

总结一下,想要彻底理解变量提升,闭包,作用域链还是需要从上下文入手。

彻底理解了上下文之后,一些不符合直觉的代码,或者特性就能对号入座了。

如果这篇文章对你有所收获,欢迎点赞评论。

相关推荐
2501_915918412 小时前
Web 前端可视化开发工具对比 低代码平台、可视化搭建工具、前端可视化编辑器与在线可视化开发环境的实战分析
前端·低代码·ios·小程序·uni-app·编辑器·iphone
程序员的世界你不懂3 小时前
【Flask】测试平台开发,新增说明书编写和展示功能 第二十三篇
java·前端·数据库
索迪迈科技3 小时前
网络请求库——Axios库深度解析
前端·网络·vue.js·北京百思可瑞教育·百思可瑞教育
在未来等你3 小时前
Kafka面试精讲 Day 13:故障检测与自动恢复
大数据·分布式·面试·kafka·消息队列
gnip3 小时前
JavaScript二叉树相关概念
前端
一朵梨花压海棠go4 小时前
html+js实现表格本地筛选
开发语言·javascript·html·ecmascript
attitude.x4 小时前
PyTorch 动态图的灵活性与实用技巧
前端·人工智能·深度学习
β添砖java4 小时前
CSS3核心技术
前端·css·css3
空山新雨(大队长)4 小时前
HTML第八课:HTML4和HTML5的区别
前端·html·html5