js变量提升和函数提升

一、对提升的理解

引擎会在解析JavaScript代码之前首先对它进行编译,编译过程中的一部分工作就是找到所有的声明,并用合适的作用域将他们关联起来,这也正是词法作用域的核心内容。

简单说就是在js代码执行前引擎会先进行预编译,预编译期间会将变量声明与函数声明提升至其对应作用域的最顶端。

提升优先度:

  1. 语言自身定义(Language-defined): 所有的作用域默认都会包含this和arguments。
  2. 函数形参(Formal parameters): 函数有名字的形参会进入到函数体的作用域中。
  3. 函数声明(Function decalrations): 通过function foo() {}的形式(通过函数表达式:var fun = function(a){console.log(a)} 和 构造函数:var fun = new Function("a",console.log(a)) 定义的函数不会提升)
  4. 变量声明(Variable declarations): 通过var foo;的形式。

二、变量提升

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
    a = 4
  }
  fn()

三、函数提升

通过function声明的函数, 在提升阶段会连函数体一起提升,而如果是函数表达式声明的只会提升名称,函数体在执行到赋值语句时才会被赋值,
function test() {
    foo(); // TypeError "foo is not a function"
    bar(); // "this will run!"
    var foo = function () { // 函数表达式被赋值给变量'foo'
        alert("this won't run!");
    }
    function bar() { // 名为'bar'的函数声明
        alert("this will run!");
    }
}
test();

四、变量提升和函数提升的顺序

思考这么一道题:

    console.log(a)
    var a = 10
    function a(){
        console.log(20)
    }

你觉得这个打印出来的a会是什么?

要是不知道提升的先后顺序,那肯定觉得输出的是10。这里就说一个知识点:你不知道的JavaScript(上卷)一书的第40页中写到:函数会首先被提升,然后才是变量。也就是说,同一作用域下提前,函数会在更前面。尽管a=10,在函数a的前面定义的,但是提升的时候还是先提升函数。所以这道题输出函数本身,以上代码等同于以下代码:

    function a(){
        console.log(20)
    }
    var a //由于上面函数已声明a,相同的变量名声明会被直接忽略
    console.log(a) //输出函数体
    a = 10

再来看一个例子,加深理解:

function a(){
  console.log(10);
}
var a;//再次声明a,并未修改a的值,忽略此处声明
console.log(a)//输出函数本体
a();//函数声明提前,可调用,输出10
a =3;//这里修改值了,a=3,函数已不存在
console.log(a);//输出3
a = 6;//再次修改为6,函数已不存在
a();//a已经为6,没有函数所以没法调用,直接报错

五、为什么会有提升

搬运:

下面是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