JS变量作用域
变量作用域
JS有函数作用域,但是没有块作用域的概念。
值得注意的是,显示声明在函数里头的变量他是局部变量,若在函数里头直接使用未声明的变量则会隐式的声明成全局变量。
代码演示:
{
var a = '其实我是全局作用域变量a';
var b = '其实我是全局作用域变量b';
}
console.log(a);
(function fun(){
var b = '局部作用域b';
c = "其实我是全局作用域c"
console.log(a);
console.log(b);
return fun;
})()
console.log(c);
运行结果:
注意:
- JS没有块作用域;
- 没有显示声明在函数里头的变量会被隐式声明全局变量。
ES(2015)6 const和let
在 ES6 之前,JavaScript 只有两种作用域: 全局变量 与 函数内的局部变量;
现在有了ES6的const和let,用该关键字在语句块进行声明的变量则作用域范围只在该语句块内可见。
代码演示:
{
const a = "const";
let b = "let";
console.log(a);
}
console.log(a);
运行结果:
const定义常量与使用let 定义的变量相似。二者都是块级作用域
- const
const声明的变量必须进行初始化,const声明的变量不允许被重新赋值。 - let
let声明的变量可以不进行初始化,也可以进行重新赋值。
变量提升(hoisting)
变量没有被声明之前,也可以使用。
scope = "global"
var scope
console.log(scope)
//输出结果:global
变量提升只是对变量的声明提前了,而赋值并没有被提前。
console.log(scope)
var scope = "global"
//输出结果:undefined
非函数变量的提升比较容易明白,函数里的变量提升,你注意过?
var scope = "global"
function f(){
console.log(scope);
var scope = "local";
console.log(scope)
}
f()
函数里的变量提升会将该变量声明提升到函数体的顶部,同时因为函数声明了该变量,那他就会取函数里的局部变量scope而不去打全局变量scope的注意了,但是因为提升的只是声明而不是初始化,所以输出undefined。
其实相当于这种情况了:
var scope = "global"
function f(){
var scope
console.log(scope);
scope= "local";
console.log(scope)
}
f()
作用域链
首先得明白,JavaScript是基于词法作用域的语言;怎么来理解这句话呢?
通俗来说,JS代码书写的时候就决定了作用域链,而不是取决运行的位置。
例如下面的案例:
fun1一开始是放在外头的,fun1输出的num的应该是全局作用域上的num。
首先在fun1函数作用域去找,没有就去全局变量去找,因为全局作用域没有定义num所以抛出ReferenceError异常;
尽管fun1是运行在fun2里面的,也尽管fun2作用域里有定义num;他认的还是fun1定义时候的作用域;
function fun1(){
console.log(num)
}
function fun2 (){
var num = "fun2"
fun1()
}
fun2()
将fun1放到fun2里面取声明,则此时fun1没有num,则会去上一层作用域去寻找,上一层作用域是fun2作用域,所以输出的是fun2中的num
function fun2 (){
var num = "fun2"
function fun1(){
console.log(num)
}
fun1()
}
fun2()