【JS基础】面试基本功之有趣的变量提升

83 阅读4分钟

前言

相信很多前端er都经历过这样的面试场景:

面试官:说一说let、var的区别? 我:let是ES6的,具有块级作用域的概念,且没有变量提升的特性。var有变量提升的特性。 面试官:来展开说说变量提升? 我:阿巴阿巴阿巴。。。

今天我们来彻底搞清楚变量提升,以后面试官再问起来,我们也能五花八门的说啦

提升

首先我们应该明确一点,提升的仅仅是声明,其次,提升这件事是发生在变量所声明的当前作用域内。可以简单理解为引擎在编译阶段会有一些优化行为,比如预先收集作用域中声明的信息,为了之后更快的找到和使用它们。 有同学开始问了:“到底啥是变量提升,为啥我平时都没见过?”,举个栗子,思考下面代码执行后打印的结果。

    console.log('1', name)
    var name = 'jack'
    getName()
    function getName () {
      console.log('2': name)
    }

让我们自上而下分析代码。第一行的变量name会打印undefined,因为第三行的声明提升到了最前面。到第二行结束,name才完成了赋值操作。注意到了吗?var name = 'jack'虽然是一句代码,但实际上它分为两步,先声明(存在提升),在赋值(不会被提升)。接着到第三句代码,执行函数,这时全局变量name已经完成赋值所以打印出‘jack’。

如果我们把第三行代码与第二行代码调换位置,第二个打印结果又是什么呢?大家可以思考下。下面我们具体来看看提升这件事。

声明提升

我们知道,使用一个未声明的变量,将会报错ReferenceError: xx is not defined,而使用一个声明但为赋值的变量,会返回undefined。我们也知道函数定义的方式有 函数声明 和 函数表达式,注意函数表达式不会被提升。

变量声明

首先来看下变量声明提升,我们对它进行变形,可以轻松得到打印结果。

  num = 0
  var num
  console.log(num)
  
  count = 1
  var count = 2
  console.log(count)

通过变量声明提升的原则上述代码等价于以下代码:

  var num
  num = 0
  console.log(num) // 0
  
  var count
  count = 1
  count = 2
  console.log(count) // 2

函数声明

再来看下函数声明提升,以下代码,思考执行后的打印结果:

  getAge(1)
  getCount(1)
  
  // 函数表达式 + 具名函数
  var getAge = function toAge (index) {
    console.log(index)
  }
  // 函数表达式 + 匿名函数
  var getNum = function (index) {
    console.log(index)
  }
  // 函数声明
  function getCount (index) {
      conosle.log(index)
  }
  getAge(2)
  getCount(2)

同样我们利用声明提升的原则进行变形,得到如下代码:

  // 函数声明
  function getCount (index) {
      conosle.log(index)
  }
  var getAge
  var getNum
  getAge(1) // getAge is not a function
  getNum(1) // getNum is not a function
  getCount(1) // 1
  
  // 函数表达式 + 具名函数
  getAge = function toAge (index) {
    console.log(index)
  }
  // 函数表达式 + 匿名函数
  getNum = function (index) {
    console.log(index)
  }
  getAge(2) // 2
  getNum(2) // 2
  getCount(2) // 2

正如我们前面说的,函数表达式没有提升,所以在定义之前执行函数会报类型错误,因为此时他们只有变量提升了,getAgegetNum 此时为undefined

声明优先级

当变量声明和函数声明相遇,函数声明才是老大哥前排坐~

console.log(a) // [Function: a]
var a = 2
function a () {}
console.log(a) // 2

注意,函数声明优先于变量声明,也就是说,函数声明会处于作用域顶部,其次才是变量声明。

总结

通过上面的各个代码示例,相信对变量提升有了一定的了解,可以变换示例中代码的顺序查看输出结果的变化,来考察自己是否真的理解了。只要我们把握声明提升的原则,就能以不变应万变。下面简单总结以下:

  1. var具有变量提升的特性,会把变量声明提升到当前作用域的最前面,但是赋值操作不会被提升;
  2. 函数声明会被提升,但是函数表达式不会被提升,无论函数表达式后面跟着是具名函数还是匿名函数都不会被提升。
  3. 函数声明提升的优先级高于变量声明,函数声明会被提升到当前作用域的最顶部,其次才是变量声明。

靓猫镇楼,还望轻拍~在评论区一起分享学习交流吧~

WechatIMG463.jpeg