浅谈JS中的变量提升

310 阅读3分钟

变量提升是面试中非常常见的问题
本篇文章主要讲的就是变量提升以及函数提升

  • 说到变量提升,我们就得先了解JS里,一句代码是如何运行的
  1. 代码一定是逐行运行的
  2. 分为编译阶段和执行阶段,编译阶段先发生,有先后顺序
  3. 有些代码是编译阶段要运行的代码,比如变量声明
  4. 作用域的概念
    • 代码在运行的时候有个作用域
    • 作用域也叫socpe
    • 作用域是一个对象
    • 作用域里面存放当前代码等下在执行上下文中的所有变量的引用
  5. 在执行代码时会涉及到变量的查找
  var myName;// 编译阶段   JS变量的类型由值决定,在编译阶段默认为undefined
  myName = '极客';// 执行阶段

所谓的变量提升,是指在JS代码执行中,JavaScript引擎把变量的声明部分和函数的声明部分提升到代码开头的行为,变量提升后,会给变量设置默认值undefined

接下来举几个例子

变量提升

// 原代码
console.log(num);// undefined
var num = 123;
// 编译后
var num = undefined;//声明提到作用域顶端
console.log(num);
num = 123;// 保留赋值语句

函数提升

具名函数的声明有两种方式

  1. 函数声明式
  2. 函数字面量式

函数声明式变量提升

showName();
function showName() {
  console.log(1);
}
//输出结果1
// 编译后
// 函数声明的优先级高于变量声明的优先级,并且函数声明和函数定义的部分一起被提升
function showName(){
  console.log(1);
}
showName();

函数字面量式变量提升

showName();
var showName = function(){
  console.log(2);
}
// 报错:TypeError: showName is not a function
//编译后
var showName = undefined;//声明提升
showName();
showName = function(){//保留赋值语句
  console.log(2);
}

综合题型

showName()
var showName = function() {
  console.log(2);
}
function showName() {
  console.log(1);
}
showName()
//1 2

分析

变量提升部分

function showName(){
  console.log(1);
}

可执行代码片段

showName()
//去掉var声明部分,保留赋值语句
showName=function(){
  console.log(2);
}
showName();

注意:var showName尽管出现在function showName()...的声明之前,但是他是重复的声明(因此被忽略了),因为函数声明会被提升到普通变量之前

注意

对变量用 var 和 let 进行变量声明会有区别,当你用 let 去实验变量提升时,你会发现 let 定义的变量声明并“没有”发生变量提升,但事实真是如此吗?
其实, let 确实没有发生变量提升,但是 let 变量提升的空间是一个临时暂死区,没有代码激活它是不能够调用的。
归根结底, let 是用来修正变量提升bug的方案。原因是JS的机制无法改变,既让传统的错误可以运行,有同时出新的方案。

总结

  1. 所有的声明都会提升到作用域的最顶上去。
  2. 函数声明的优先级高于变量声明的优先级,并且函数声明和函数定义的部分一起被提升。
  3. 变量提升是发生在创建变量对象的过程中,会先扫描函数声明,再扫描变量声明。
  4. 同一个变量只会声明一次,其他的会被忽略掉或者覆盖掉。
  5. var 与 let 变量声明有区别。

(注:本文是博主初学JS所学知识,有错误之处在所难免,望诸位大佬指正,本人也会定期更新新的文章以及修改前文错误,欢迎大家来评论区一起讨论学习~)