前端核心知识点2:变量提升


一.什么是变量提升?

console.log(a)  // undefinedvar a = 10

定义:一个JS代码文件的运行分为编译阶段和执行阶段,而变量提升发生在编译阶段,当JS文件被编译时,会把变量的声明部分"提升"到代码的开头 并给这个变量赋值undefined。

在变量提升阶段:带 var 的只声明还没有被定义,带 function 的已经声明和定义。所以在代码执行前有带 var 的就提前声明,比如这里的 a 就赋值成 undefined,在代码执行过程中遇到创建函数的代码浏览器会直接跳过。

var a =12var b = ab = 1function sum(x, y) {    var total = x + y    return total}sum(1, 2)

变量提升只发生在当前作用域。比如:在页面开始加载时,只有全局作用域发生变量提升,这时候的函数中存储的都是代码字符串。

二. 带 var 和不带 var 的区别

  • 全局作用域中不带var声明变量虽然也可以但是建议带上 var声明变量,不带 var 的相当于给window对象设置一个属性罢了。

  • 私有作用域(函数作用域),带 var 的是私有变量。不带 var 的是会向上级作用域查找,如果上级作用域也没有那么就一直找到 window 为止,这个查找过程叫作用域链

  • 全局作用域中使用 var 声明的变量会映射到 window 下成为属性。

a = 12  // == window.aconsole.log(a)  // 12console.log(window.a) // 12
var a = b =12 // 这里的 b 也是不带 var 的。/* 相当于*/var a = 12;b = 12

三. 等号左边下的变量提升

函数左边的变量提升

  • 普通函数下变量提升示例

print()function print(){    console.log('面试宝典')}print()//面试宝典  因为带function的已经进行了变量提升
  • 匿名函数下的带=的变量提升

print()var print = function() {    console.log('面试宝典')}print()/*输出    Uncaught TypeError: print is not a function///同样由于变量提升机制带 var 的 print 是一开始值是 undefined,// 所以 print() 这时还不是一个函数,所以报出 类型错误TypeError

四. 条件判断下的变量提升

  • if else 条件判断下的变量提升

console.log(a)if(false){    var a = '面试宝典'}console.log(a)/* 输出    undefined    undefined/

在当前作用域中不管条件是否成立都会进行变量提升

  • if 中 () 内的表达式不会变量提升

var y = 1if(function f(){}){     console.log(typeof f)  // undefined    y = y + typeof f}console.log(y)  // 1undefined

判断的条件没有提升,所以条件内部的 f 是未定义

  • 新版浏览器中,在条件判断块级作用域之外使用条件内函数。

  • 为了迎合 ES6 语法只有 JS 执行到条件语句,判断条件是成立的才会对条件内的函数赋值,不成立不被赋值只被定义成undefined

console.log(print())    // == window.print()if(true){    function print() {        console.log('面试宝典')    }}console.log(print())/* 输出    undefined    面试宝典    undefined*/

第一行代码 console.log(print()) 相当于 window.print() 是内置函数,返回值就是 undefined

console.log(a)console.log(p())if(true){    var a = 12    function p() {        console.log('面试宝典')    }}/** undefined* Uncaught TypeError: p is not a function*/

全局下不管条件是否成立都会对带 var, function 进行变量提升,所以输出的 a是 undefined。JS 还没对条件语句进行判断,同样 p 也是undefined 相当于 undefined() 所以会报错 TypeError


五. 重名问题下的变量提升

  • 带 var 和带 function 重名条件下的变量提升优先级,函数先执行。

console.log(a);   var a=1;function a(){    console.log(1);}// 或console.log(a);   var a=1;function a(){    console.log(1);}// 输出都是:ƒ a(){ console.log(1);}


var 和 function 同名的变量提升的条件下,函数会先执行。所以输出的结果都是一样的。换一句话说,var 和 function 的变量同名 var 会先进行变量提升,但是在变量提升阶段,函数声明的变量会覆盖 var 的变量提升,所以直接结果总是函数先执行优先。

  • 函数名和 var 声明的变量重名

var fn = 12function fn() {    console.log('面试宝典')}console.log(window.fn)fn()/* 输出*  12*  Uncaught TypeError: fn is not a function/


思路:带 var 声明的和带 function 声明的其实都是在 window 下的属性,也就是重名了,根据变量提升的机制,fn的变量提升过程是fn =>undefined =>oxffeeaa,随后JS 代码自上而下执行时此的 fnfn = 12,输出的window.fn = 12,所以 fn() ==> 12() 又是一个类型错误 TypeError


留一道思考题(字节)

let a = 0, b = 0;function fn(a) {  fn = function fn2(b) {    console.log(a, b)    console.log(++a+b)  }  console.log('a', a++)}fn(1); // a, 1fn(2); // 2, 2   5