console.log(a) // undefined
var a = 10
定义:一个JS代码文件的运行分为编译阶段和执行阶段,而变量提升发生在编译阶段,当JS文件被编译时,会把变量的声明部分"提升"到代码的开头 并给这个变量赋值undefined。
在变量提升阶段:带 var
的只声明还没有被定义,带 function
的已经声明和定义。所以在代码执行前有带 var
的就提前声明,比如这里的 a
就赋值成 undefined
,在代码执行过程中遇到创建函数的代码
浏览器会直接跳过。
var a =12
var b = a
b = 1
function sum(x, y) {
var total = x + y
return total
}
sum(1, 2)
变量提升只发生在当前作用域。比如:在页面开始加载时,只有全局作用域发生变量提升,这时候的函数中存储的都是代码字符串。
全局作用域中不带var
声明变量虽然也可以但是建议带上 var
声明变量,不带 var
的相当于给window对象设置一个属性罢了。
私有作用域(函数作用域),带 var
的是私有变量。不带 var
的是会向上级作用域查找,如果上级作用域也没有那么就一直找到 window 为止,这个查找过程叫作用域链
。
全局作用域中使用 var
声明的变量会映射到 window 下成为属性。
a = 12 // == window.a
console.log(a) // 12
console.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 = 1
if(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 = 12
function fn() {
console.log('面试宝典')
}
console.log(window.fn)
fn()
/* 输出
* 12
* Uncaught TypeError: fn is not a function
/
思路:带 var
声明的和带 function
声明的其实都是在 window 下的属性,也就是重名了,根据变量提升的机制,fn
的变量提升过程是fn =>undefined =>oxffeeaa
,随后JS 代码自上而下执行时此的 fn
是fn = 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, 1
fn(2); // 2, 2 5