目录
定义
作用域是在运行代码中某些特定部分中变量、函数、对象的可访问性。通俗点讲,可以把作用域理解为一个独立盒子,隔离变量,让变量不会外泄和暴露出去,所以不同作用域下同名变量不会发生冲突。
ES6之前JavaScript没有块级作用域,只有全局作用域和函数作用域(ES6提供块级作用域,可通过新增命令let和const体现)
全局作用域
代码中任何地方都能访问到的对象拥有全局作用域,一般来说如下几种情形拥有全局作用域:
1.函数外部定义的变量
2.函数内未定义直接赋值的变量
3.所有window对象的属性
var a="最外层变量"; //最外层变量
function fun(){ //最外层函数
var b="内层变量"; //定义内层变量
c="未定义直接赋值的变量"; //"未定义直接赋值的变量"
}
fun(); //调用函数
console.log("a=",a); //a= 最外层变量
console.log("c=",c); //c= 未定义直接赋值的变量
上述全局变量一直占用内存,直到浏览器页面关闭才会释放
局部作用域
与全局作用域相反,一般只能在固定代码片段内访问,常见于函数作用域中
函数作用域
函数作用域内,对外封闭,从外层无法直接访问函数内部作用域,如需访问需要通过return或者利用闭包函数来实现
var a="最外层变量"; //最外层变量
function fun(){ //最外层函数
var b="内层变量"; //定义内层变量
c="未定义直接赋值的变量"; //"未定义直接赋值的变量"
}
fun(); //调用函数
console.log(b); //报错 ReferenceError: b is not defined
块级作用域
ES6新增let和const命令,可用于创建块级作用域变量,使用let命令声明的变量指再let命令所在代码块内有效(let声明语法与var语法一致,可以使用let代替var进行变量声明,但会将变量作用域限制在当前代码块中),ES6中新增的块级作用域用“{}”表示。
//用let声明变量,变量不会提升到代码块顶部
console,let(a); //ReferenceError: let is not defined
let a=2;
//用let声明变量,不允许外部访问块级作用域内部变量
for(let i=0;i<10;i++){
console.log(i);
}
console.log(i); //ReferenceError: i is not defined
ES6中let和const还有一个特点:不允许反复声明
//var可以反复声明进行覆盖
function testVar(){
var a=1;
var a=2;
console.log(a); //2
}
testVar();
//let、const不允许反复声明
function testLet(){
let a=1;
let a=2;
console.log(a); //SyntaxError: Identifier 'a' has already been declared
}
testLet();
function testConst(){
const a=1; //改成var a=1或者let=1也是同样的效果,相同变量不能反复声明
const a=2;
console.log(a); //SyntaxError: Identifier 'a' has already been declared
}
testConst();
作用域链
定义
JavaScript上每个函数执行时,会在自己创建的活动对象上搜寻对应属性值,若没找到则往父函数的活动对象上找,仍未找到则再上一层,直至找到window全局作用域(无论是否找到,停止查找过程),这一过程可以看作是一条链,也称作用域链。
查找方式
当我们需要使用声明的变量时,js会从所在的域一层一层向外层域查找,如果找到了就进行使用,不再进行继续查找
var value='1';
function test(){
var value='2';
console.log(value); //2
function innertest(){
var value='3';
console.log(value); //3
}
return innertest();
}
test();
console.log(value); //1
层级关系如下所示:
注意:查找变量时,要去创建这个函数的作用域中去取值,而不是调用
var a=2;
function test(){
var b=5;
function fun(){
console.log(a+b); //7
}
return fun;
}
var m=test(); //test()返回fun函数赋值给m
var b=10;
m(); //执行m()-->调用fun函数
如同上例, test()返回fun函数赋值给m,执行m()调用fun函数,fun函数的变量回到其创建的作用域中去寻找,向上在test作用域中找到变量b=5,再继续向上找到全局作用域中变量a=2,故得出a+b=7,与之后在全局作用域声明的b变量无关。分析图如下所示: