zoukankan      html  css  js  c++  java
  • 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还对变量提升和函数提升做了总结:

     大概是说,变量提升是人为实现的问题,而函数提升在当初设计时是有目的的。

    不积跬步无以至千里
  • 相关阅读:
    转载:linux or unit 连接 windows的远程桌面-rdesktop(略有修改)
    Excel技巧
    Linux实用配置(ubuntu)
    转载:VMware linux 虚拟机中修改MAC地址
    windows技巧
    cdoj1099
    hdu1160(问题)
    c#学习笔记
    hdu1176
    qsort(),sort() scanf();
  • 原文地址:https://www.cnblogs.com/lyt0207/p/12033956.html
Copyright © 2011-2022 走看看