我使用了const为什么还有变量提升?

申啸天
  • 18

今天在看老代码的时候发现了一点疑问

// a === 1
const b = () => {
    a()
}
const a = () => {console.log(1)}
b()

读到上述代码发现const理论上不会被提升到代码顶部,为什么b函数内的a会被正确执行?

// a is not defined
const b = () => {
    a()
    const a = () => {console.log(1)}
}
b()

这段代码符合我的预期,在const之前就调用了a 。所以a不会执行

我查阅了一下资料。认为和es6的代码块作用域有关系,可是自己也没有琢磨明白。希望大佬给予指点

回复
阅读 1.6k
5 个回答
// a === 1
const b = () => {
    a()
}
b()
const a = () => {console.log(1)}

这样试试???

首先 b a在同一个作用域中, 其次你的b调用的时候同作用域的a已经有了。所以你的暂时性死区是包含a的声明的,
所以你可以把b的执行放在a前面,那么就会在a的死区之外执行,就会报错了兄弟,并不是你声明的时候没有它就是没有,而是看作用域的。

没有变量提升,你执行b()的时候,a已经声明了。

image.png

代码版本:

const b = () => {
    a()
}
const a = () => console.log(1)
b()


// 我的对变量声明的理解是,视为写在词法作用域中第一行,并注册一个标识符,默认值undefined
// 只不过var会直接提升到上层(跨越词法作用域),代码执行前可以进行初始化和使用
// const 和let 就不会存在“跨越词法作用域提前使用未声明变量",
// 这里由于是在变量d的词法作用域内 “声明前使用了变量c” ,所以
// 会报错 ReferenceError: Cannot access 'c' before initialization

// 而上面的变量 a 由于不是在词法作用域内声明的,声明的全局作用域的变量a,故可以运行
// 

// 在对比分析以下三种情况,会发现,
// const受词法作用域影响很大, 
// 而且 函数变量确实是不会在词法作用域内提升的   函数变量: var a = () => {}

const cos = function t() {
    sin()
    var sin = () => console.log(2) 
    // 如果使用 var 来在词法作用域内声明, 会sin is not a function,sin函数不存在
}
cos()

const j = function t() {
    k()
    function k() {
        console.log(2) 
    }
    // 如果使用 function 来在词法作用域内声明,就会视为变量提升,代码正常运行
}
j()

const d = function t() {
    c()
    const c = () => console.log(2) 
    // 使用 const 来词法作用域内声明, 会ReferenceError: Cannot access 'c' before initialization
}
d()

你可能想岔了。。

const b = () => {
    a()
}
b()
const a = () => {console.log(1)}

你这样子试试
image.png

你的第一种情况,js 引擎从上之下解析,在b() 之前就已经在当前作用域内创建好了 b、a 变量,并且分别赋值了函数的引用地址,当执行b()时,函数体内执行到 a()时会进行如下作用域查询:

  1. 先在当前作用域查询是否存在a,显然是没有的;
  2. 继续往上层作用域查找,发现存在a,其值是一个函数类型引用值,可执行 a()

与提升无关。

第一种情况,虽然a定义在b后,但是b函数执行到a()时,a显然已经是一个函数,所以正常调用。
第二种情况,b函数执行到a(),a是啥还不知道,所以自然报错。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏