js 变量提升和作用域的理解
js 中的变量提升大体可以分为两种,一种是使用 var 声明的变量,另一种是函数的变量提升,而函数的创建可以分为函数声明和函数表达式两种,这两种具有不同的变量提升,以下为本人根据自己的理解参考其他博主的博客得出的看法,如有错误欢迎指正。
使用var声明的变量
我们首先先看一段代码,
function scopeTest(){
console.log(test); // undefined
var test = 'hello';
}
scopeTest();
以上代码输出的结果是 undefined
,原因是 js 对于使用var声明的变量具有变量提升的特性,函数内部会首先声明函数内部需要的变量并赋值为undefined。以上代码等价于
function scopeTest(){
var test;
console.log(test);
test = 'hello';
}
scopeTest();
没有使用var声明的会变成全局变量
var test = 'hello';
function scopeTest(){
console.log(test) // hello
test = 'helloworld';
}
scopeTest();
console.log(test); // helloworld
函数中的 test 变量没有使用var进行声明,所以并不具备变量提升,此时打印,打印的是上层作用域的test即 hello,由于 test 是直接声明的,那么 test 会成为全局变量,覆盖掉已经有的 test ,所以为函数执行完打印 test 输出的是 helloworld
函数提升
函数的创建分为两种,一种是使用function加函数名进行声明,另一中将函数赋值给变量
首先看第一种,声明方式如下
var a=1;
function foo(){
console.log(a); //[Function: a]
a=10;
return;
function a(){ }
}
foo();
console.log(a); // 1
这边我们可以看到最后打印的出的 a 是 1 而不是函数里赋值的10,原因是函数具有变量提升的特性,以上代码等价于
var a=1;
function foo(){
function a(){ }
console.log(a); //[Function: a]
a=10;
return;
}
foo();
console.log(a); // 1
函数内部首先声明 function a 此时函数内部的 a 为function类型,此时打印 a 可以看出是一个function 接下来 a = 10 将 a 的类型转为 number 并赋值为 10;然后return 函数销毁,函数内部的 a 变量被回收。最后打印的 a 还是全局的 a
上面是使用 function 进行申明的,下面试一下使用函数表达式的方式进行声明
var a=1;
function foo(){
console.log(a); //undefined
a=10;
return;
var a = function(){ }
}
foo();
console.log(a); // 1
这边可以看到第 3 行打印的是 undefined 而不是 function,同样具有变量提升但是两者却不一样,使用函数表达式的方式进行声明函数只会定义变量,函数体和函数内容并不会携带,但是使用function加函数名的方式会将函数名和函数体一起提升到函数的头部。
以上代码等价于
var a=1;
function foo(){
var a;
console.log(a); //undefined
a=10;
return;
a = function(){ }
}
foo();
console.log(a); // 1
作用域
js 的作用域分为全局作用域和函数作用域,没有块级作用域,说起作用域就得说到作用域链。
var global='global context';
var inner='global inner context';
function foo(){
console.log(global);
console.log(inner);
var inner='inner context';
console.log(inner);
}
foo();
第4行:foo 函数内部,首先打印global,由于函数内部没有这个变量,那么会从foo函数的外部作用域开始找这个变量,然后打印。
第5行:inner这个变量,由于变量提升,所有函数的头部存在inner变量的定义,打印出undefined
第7行:inner变量赋值,打印出 inner context
与作用域息息相关的是闭包,this指向问题。