让前端飞程序员Javascript收集

Javascript之『变量提升』

2018-12-04  本文已影响14人  67a920c75520

变量声明恐怕是我们日常开发中最最经常遇到的了,那今天我们就来总结下现在js一共有哪几种变量声明的方式以及各个声明方式的特点。

ES5变量声明方式有var, function。
通过这两种方式声明的变量特点就是具有“变量提升”的效果,一般想法是一个变量是先声明后使用,然而如果采用var 或者function声明的变量和函数(函数表达式不会提升)具有提升的效果。
下面详细说明变量提升究竟是怎么产生的。

代码在引擎中运行之前都会经历词法分析阶段,这个阶段会将由字符组成的字符串分解成若干(对编程语言而言)有意义的代码块,而这些小的代码块我们可以称他们为词法单元,举个栗子给大家,比如:var age = 27;这一句通常会被分解为var、age、=、27、;空是否会被当做词法单元取决于空格在这门语言中是否有意义。接下来是语法分析阶段会将这些词法单元解析成一个树结构我们将这个树结构称之为“抽象语法树”。然后编译器会进行如下处理,首先遇到var age,编译器会询问当前作用域是否已近存在一个改名字的的变量,如果是的,编译器就会忽略该声明,如果不是的话就会要求在当前作用域的集合中声明一个新的变量,并且为这个变量命名为age。但是不会立刻给他赋值,赋值是在运行的时候才做的事情。编译阶段实际会吧所有的var声明的变量提升到前面。即var age = 27; 可以近似的看成var age;(编译阶段)age = 27;(运行阶段)。所以就会产生“变量提升”的效果了。

关于变量提升需要注意这几点:

在js中用var ,function声明的变量都将被提到函数的最顶部。(但是不会初始化)
函数声明的优先级大于变量声明的优先级(function > var )
在函数内部变量提升的优先级会小于函数参数(函数参数 > 函数内部变量提升)

下面辅以例子来具体说明

    console.log(a)
    var a = 3;

运行结果如下:

undefined

实际上等同于运行下列代码:

    var a;
    console.log(a)
    a = 3;

打印出a的时候,a已近声明(变量提升的效果)但是并未赋值,自然就是undefined了,如果没有变量提升的效果此处就会报一个reference erro的错误类型了。

再看如下代码:

   console.log(f)
 
    f()
    var f = 27;
 
   function f(){
       console.log('I am function f')
   }
 
   console.log(f);
   f = 2;
   f();

看看运行结果:

ƒ f(){
       console.log('I am function f')
   }
I am function f
27
Uncaught TypeError: f is not a function

下面我们来分析一下为什么是这个结果:
先var 和function都具有变量提升且根据我们上面的第二条原则function > var 所以第一次打印console.log(f)此时的f是一个函数;

接下来是运行f()自然就会得到f函数内打印的字符串'I am function f'再接下来就是给f赋值了此时的f = 27;打印f就会得到数字27,然后又将f的值改为2,再运行f()而此时f已近不是一个函数了,所以控制台会抱一个typeError的错误,表示我们对f的用法错了(关于各个错误类型我们后面会有一篇文章专门说明)。

下面再看看我们所说的第三点:

var age = 0;
   function foo(age) {
       console.log(age);
       var age = 20;
   }
 
    foo(27)
    console.log(age)
27
0

在函数foo中此时传入的参数age=27,根据我们上述的第三点即函数参数 > 函数内部变量提升。所以在函数内部打印出的age是传入的参数27,最后一句打印出的age自然就是0了。

有关于函数表达式是否会有变量提升,我看了很多人写的博客是说函数表达式并不会有变量提升,我并不赞同这个观点,我觉得函数表达式也会产生变量提升,事实上只要是用var 与function声明的变量都会产生变量声明,但切记用var 声明的变量不会立马赋值。看如下代码。

 console.log(foo)
    
    var foo = function () {
        console.log('I am a function foo')
    }
undefined

实际上在这儿运行的代码等同下面的代码:

  var foo;
    console.log(foo)
    
    foo = function () {
        console.log('I am a function foo')
    }

所以函数表达式也同样有变量提升的效果。

上一篇下一篇

猜你喜欢

热点阅读