引擎会在解析JavaScript代码之前首先对它进行编译,编译过程中的一部分工作就是找到所有的声明,并用合适的作用域将他们关联起来,这也正是词法作用域的核心内容。
简单说就是在js代码执行前引擎会先进行预编译,预编译期间会将变量声明与函数声明提升至其对应作用域的最顶端。
例如:
var a = 3
function fn () {
console.log(a) //undefined
var a = 4
}
fn()
js编译的时候
var a = 3
function fn () {
var a;
console.log(a) //当声明一个变量,但并不给空对象赋值就使用是它的值就是undefined
var a = 4
}
fn()
通过function声明的函数, 在之前就可以直接调用
fn2() //可调用 函数提升
function fn2() {
console.log(‘fn2()‘)
}
像下面这种情况就不能调用:
fn3() //不能调用 属于变量提升
var fn3 = function () {
console.log(‘fn3()‘)
}
fn3属于变量声明,变量提升以后值为undefined,不可调用
搬运:
下面是Dmitry Soshnikov早些年的twitter,他也对这个问题十分感兴趣, Jeremy Ashkenas想让Brendan Eich聊聊这个话题:
大致的意思就是:由于第一代JS虚拟机中的抽象纰漏导致的,编译器将变量放到了栈槽内并编入索引,然后在(当前作用域的)入口处将变量名绑定到了栈槽内的变量。(注:这里提到的抽象是计算机术语,是对内部发生的更加复杂的事情的一种简化。)
然后,Dmitry Soshnikov又提到了函数提升,他提到了相互递归(就是A函数内会调用到B函数,而B函数也会调用到A函数),
Brendan Eich很确定的说,函数提升就是为了解决相互递归的问题,大体上可以解决像ML语言这样自下而上的顺序问题。
最后,Brendan Eich还对变量提升和函数提升做了总结:
大概是说,变量提升是人为实现的问题,而函数提升在当初设计时是有目的的。
原文:https://www.cnblogs.com/lyt0207/p/12033956.html