变量提升-->JavaScript 变量的另一个不同寻常的地方是,你可以先使用变量稍后再声明变量而不会引发异常。这一概念称为
变量提升
/**
* 例子1
*/
console.log(x === undefined); // true
var x = 3; 这个例子等价于:
var x;
console.log(x === undefined); // true
x = 3;var myvar = "my value";
(function() {
console.log(myvar); // undefined
var myvar = "local value";
})();
这个也是一个变量提升的例子,变量会提升到函数的最顶部,等价于:
var myvar = "my value";
(function() {
var myvar;
console.log(myvar); // undefined
myvar = "local value";
})();
这个myvar的作用域是在我们匿名函数里面,也是undefined
再看一个例子:
我们要记住在函数中的作用域是函数作用域,第一个输出0 是外部的i
第二个为undefined是因为inner函数作用域中我们重新定义了变量i,它提升作用域到函数顶部,类似:
function inner(){
var i ;
console.log(i)
i=1
console.log(i)
}因此打印undefined,然后再打印1
如果我们不写var ,那么i只是一个赋值操作,就直接显示为0 0 1 1了,这个需要注意,var i 新创建了一个作用域内的变量i,这个和全局作用域的i是不同的东西
再来一个例子:

这个输出的应该是undefined,为啥呢?因为函数里面var是函数作用域的,变量提升到函数的顶部了,因此未定义undefined
那么如果我们的var 换成let会怎么样呢?还是报undefined么还是其他?
var myvar = "my value";
(function() {
console.log(myvar); // ReferenceError: myvar is not defined
let myvar = "local value";
})();let 这个不会做变量提升动作,因此直接会报错误(在函数作用域中认为这个myvar还是一个新的变量,但是不会提升它,所以这里没有打印出全局的这个值),报错之后后续code不会执行
重复声明

上面的输出其实是:1 2 2。虽然看起来里面x申明了两次,但上面说了,js的var变量只有全局作用域和函数作用域两种,且申明会被提升,因此实际上x只会在最顶上开始的地方申明一次,var x=2的申明会被忽略,仅用于赋值。也就是说上面的代码实际上跟下面是一致的。我们可以认为这个是:
var x = 1
console.log(x)
if(true){
x = 2
console.log)(x)
}
console.log(x)函数提升
定义函数有两种方式:函数声明和函数表达式
js中函数的声明并定义
function fnc() {}
函数表达式:
var fnc = function(){}
/* 函数声明 */
foo(); // "bar"
function foo() {
console.log("bar");
}
这个我们可以看成是:
function foo(){
console.log("bar")
}
foo()
如果是函数表达式那么是不提升的,请看下面:/* 函数表达式 */
baz(); //TypeError: baz is not a function
var baz = function() {
console.log("bar2");
};其实我们这里可以直接理解成为:
var baz;
baz(); //TypeError: baz is not a function
baz = function() {
console.log("bar2");
};
当成一个变量提升到最顶部,然后必然baz不是一个函数,导致类型调用错误
为什么函数定义能提升,函数表达式不能提升呢?
函数声明提升会在编译阶段把声明和函数体整体都提前到执行环境顶部,所以我们可以在函数声明之前调用这个函数
函数表达式,其实就是变量声明的一种,声明操作会被提升到执行环境顶部,并赋值undefined。赋值操作被留在原地等到执行。
那么如果同时有函数和变量提升,以哪个为准呢?
例如:
console.log(foo);//[Function: foo]
function foo() {
}
var foo = 'hello world'打印的是一个函数,可以理解为:
function foo() {
}
console.log(foo);//[Function: foo]
foo = 'hello world'
原因:1、函数声明被提升到最顶上;2、申明只进行一次,因此后面var foo='i am text'的申明会被忽略,函数声明优先于变量声明,由于声明只执行一次,因此执行的是函数的声明
那么如果是函数定义呢?
等价于:
var foo
console.log(foo)
foo = function(){}
foo='i am text'
输出的是undefined