1、为什么会产生变量提升?
1.1 javascript代码解释执行过程
其实,产生变量提升的原因与javascript代码解释执行过程有关:
javascript是由浏览器解释执行的脚本语言,不同于java c,需要先编译后运行,
javascript 由浏览器js解释器进行解释执行,总的过程分为两大块,预编译期和执行期
js执行过程分为
预编译期和执行期(以代码块为单位,边解释边执行),在预编译期,js解释器会对本代码段内所有的 声明的变量和方法进行处理,将变量和方法提到对应的作用域的最前面,该过程只是对变量进行声明,并不会进行初始化或者赋值(缺省值默认为undefined)
例:
console.log(a,"a") //undefined "a"
var a = "我是a"
因为变量a的声明被提到了作用域顶端,并且不会进行初始化或者赋值。上面代码编译后应该是下面这个样子
var a //将变量声明提升到对应作用域最前面,缺省值默认为undefined
console.log(a,"a") //undefined "a", 所以这里输出的a为 undefined
var a = "我是a"
1.2 javascript作用域
再看一个例子:
console.log(a);//undefined
var a = 1;
console.log(a); //1
(function(){
console.log(a); //undefined
var a =2;
console.log(a); //2
})()
上面的代码经过编译后就是这样子
var a //将变量a声明提升到对应作用域最前面,缺省值默认为undefined
console.log(a);
var a = 1;
console.log(a);
(function(){
var a //将变量a声明提升到对应作用域最前面,缺省值默认为undefined
console.log(a);
var a =2;
console.log(a);
})()
//所以依此输出的为 undefined 1 undefined 2
上面这个例子除了与JS代码执行过程有关,还与JS的作用域有关,JavaScript是函数级作用域,在函数才会创建新的作用域。所以函数外面声明的a与函数里面声明的a不相同
块级作用域:进入到一个块时,就像if等语句(用{}包起来的代码),在这个块级作用域中会声明新的变量,这些变量不会影响到外部作用域。如C语言
函数级作用域: 进入到一个函数时,在这个函数作用域中会声明新的变量,这些变量不会影响到外部作用域。
2、 函数提升
函数的定义方式:
1、函数关键字(function)语句:function(){}
2、函数字面量:var fn =function(){} 。(变量形式声明)
使用函数关键字(function)语句定义
bar()
function bar() {
console.log(1);
}
//输出结果1
相当于这样
function bar() {
console.log(1);
}
bar()
//输出结果1
使用变量式声明函数
bar()
var bar = function() {
console.log(1);
}
// 报错:TypeError: bar is not a function
使用变量式声明函数,此时函数就相当于一个变量。所以使用变量式声明的函数,和变量提升是一样的,所以上面例子相当于这样
var bar //将变量bar声明提升到对应作用域最前面,缺省值默认为undefined
bar()
var bar = function() {
console.log(1);
}
// 报错:TypeError: bar is not a function
通过上面两个例子可以看出,只有通过函数关键字(function)声明的函数才存在函数提升。函数声明会提升到作用域最前边,并且将声明内容一起提升到最上边。
补充一点,当var fn与function fn(){}撞在一起时,哪个更优先?
例如下面两个例子
var fn
function fn(){}
console.log(fn)
function fn(){}
var fn
console.log(fn)
这两段代码的输出分别是什么?
答案是两个输出的都为 function fn(){}
结论:function 比 var 牛逼,function的优先级更高
总结
- 在JS
预编译期,js解释器会对本代码段内所有的 声明的变量和方法进行处理,将变量和方法提到对应的作用域的最前面,该过程只是对变量进行声明,并不会进行初始化或者赋值(缺省值默认为undefined)- 所有的声明都会提升到作用域的最顶上去。
- 同一个变量只会声明一次,其他的会被忽略掉或者覆盖掉。
- 函数声明和函数定义的部分一起被提升。
- JS是函数级作用域。在函数作用域中会声明新的变量,这些变量不会影响到外部作用域。