变量提升:
首先我们要知道js执行前有一个 “预编译” 过程,
预编译主要有两个任务:
- 声明所有var变量(初始为undefined)。
- 解析定义式函数语句。(后面会讲到什么是定义式函数语句)
也就是说变量的提升 是在js的预编译阶段完成的。
变量提升的概念: 函数和变量的声明会被js的解释器放到最前面。
例子:下面aa第一次打印时输出undefined ; 原因是由于第二句var aa=1 实际上是在代码的最开始 var aa; 然后在var aa=1 的地方执行 aa=1;
而第二个bb则没有这个过程,所以会报错
console.log(aa) // undefined
var aa=1
console.log(aa) // 1
console.log(bb) // 报错:"ReferenceError: bb is not defined"
在看一个例子
function fn1() {
a = 1;
console.log(a); // 1
console.log(window.a); // window对象里没有a 输出undefined
var a = 5;
console.log(a); // 5
}
fn1();
这个实际上是先var a; 然后进行了两次赋值,a=1, a=5
function fn1() {
console.log(a); // ReferenceError: a is not defined"
a = 5;
console.log(a); // 如果不考虑报错,输出5
}
fn1();
变量提升一定是要有变量声明的过程,
如var xx=5。像上面栗子中如果不声明直接对a赋值,那么a将变成一个全局对象。不存在变量提升。所以第一个console会报错。
看看这两个的区别:
//全局作用域下
a = 5;
//全局作用域下
var a = 5;
都在全局作用域下执行两端代码有何区别?
- a=1相当于window.a=5。为全局window对象添加了一个属性a值为5
- var a=5相当于在全局作用域中声明了变量a,在整个作用域中都有效
- 后者比前者多了一个声明的行为
- 前者没有变量提升过程,提前访问会报错,后者有变量提升
补充——es6中的变量提升
es6 新增块级作用域,let 和 const 声明的变量会产生块级作用域。
并且 let 和 const 声明的变量不会做变量提升。所以就会出现暂时性死区。
foo(10)
function foo(num) {
// 暂时性死区
console.log(foo)
// 暂时性死区
let foo = num
}
此时,浏览器报错foo is not defined。这就是因为 let 和 const 声明的变量不会做变量提升,所以变量的声明和赋值都是在console.log 之后,所以访问一个不存在,没有声明的变量时,浏览器自然会报错。
函数提升
先看定义函数的两种方式:
| 函数声明式 | 函数表达式 | |
|---|---|---|
| 写法 | function fn(){ } | var fn = function fn(){ } |
| 函数名 | 必须 | 非必须 |
| 是否能在声明前调用 | 可以 | 不可以 |
| 函数提升 | 声明,函数体都提升 | 声明提升,函数体不提升 |
特别注意的是:
变量提升中,变量赋值并没有被提升,只是声明被提升了。
但是,函数提升有点不一样,在定义式声明函数中,函数体也会一同被提升。
看个栗子
test(); // 打印了111111
function test(){
console.log(111111);
}
所以会出现上面的情况,先执行test函数,然后声明,但是实际上函数确实被执行了,这就是与变量提升不同的点,函数提升不止声明提升,函数体也会一同被提升。
特别注意通过函数表达式创建的函数只会将声明提升,函数体不会提升
fn3(); // "TypeError: fn3 is not a function"
var fn3 = function(){
}
再看这两个例子
function bar() {
console.log('bar1')
}
var bar = function () {
console.log('bar2')
}
bar() // bar2
var far = function () { // 函数表达式
console.log('far2')
}
function far() { // 函数声明式
console.log('far1')
}
far() // far2
结果全部输出 bar2,在预编译阶段,
结论:变量 bar 进行声明,但不赋值。函数bar进行创建并提升。运行阶段bar被赋值。
作用域
在ES6之前,JavaScript没有块级作用域(一对花括号{}即为一个块级作用域),只有全局作用域和函数作用域。










网友评论