javascript变量提升
在日常开发中有时候可能会遇到下面的情况:
var var1 = 1;
function fn() {
console.log(var1);
var var1 = 2;
console.log(var1);
}
fn();
// undefined
// 2
第一次遇到的人可能会觉得很奇怪(因为外面定义了同名变量,所以第一次应该打印出1),为什么会有这种情况出现呢?我们把代码改成下面的样子就方便理解了:
var var1 = 1;
function fn() {
var var1;
// 如果不给变量赋初值,它的值就是undefined
console.log(var1);
var1 = 2;
console.log(var1);
}
这就是javascript中的变量提升。 MDN上的解释是"变量提升是JavaScript将声明移至作用域scope (全局域或者当前函数作用域) 顶部的行为"。
除了变量,函数也存在变量提升的情况,但是如果用函数直接量法定义一个函数,会报类型异常:
function fn() {
fnInner();
var fnInner = function() {
console.log("inner fn");
}
}
fn();
// 类型异常(undefined is not a function)
就像刚才说的,fnInner会被放到函数体的第一行,但是没有赋初值,所以就成了undefined。
但是如果用正常函数声明的方法就可以被正确调用,就像下面的样子:
function fn() {
fnInner();
function fnInner() {
console.log("inner fn");
}
}
fn();
甚至有次在angularjs源码中(1.x)看到下面的使用方式:
function x() {
// do something
return {
attr1: fn1(),
attr2: fn2()
// ...
};
function fn1() {
// do something
return {
// ...
};
}
function fn2() {
// do something
return {
// ...
};
}
}
当时一看觉得很诧异,主要是一般return以后不能再写代码了,但是又仔细一想,是变量提升的作用。
即使变量提升给我们带来了很大的便利(函数可以在被调用之后声明),但是我们也应该养成变量先定义后使用的习惯,一是提升代码的可读性(不至于在函数体内这里定义一个变量那里定义一个变量的),二是不至于出现一些意想不到的错误或异常。
在ES6中,如果我们用let来定义变量,但是在它定义之前使用,就会报错(使用typeof也会异常),可能ES6也强制我们养成"先定义后调用"的习惯吧。