做用域:每一个函数有本身执行环境(我的理解即做用域),而其执行环境决定了那个环境中的变量和函数能够访问的数据的权限。前端
做用域链:从当前执行环境往外部检索(当前环境为此做用域链的最前端,全局环境为做用域链尾部),第一种状况检索成功,直到检索到对应变量为止;第二种状况检索失败,即找到全局环境还未找到相对应的变量,返回not defined的错误。浏览器
例:
function scopetest1() {函数
var test1 = 1; //可访问test1blog
function scopetest2() {作用域
var test2 = 2; //可访问test1以及test2io
function scopetest3() {console
var test3 = 3; //可访问test1 test2以及test3function
test2 = test3;test
console.log(test2); //3匿名函数
console.log(test3); //3
}
scopetest3();
test3 = 5;
console.log(test3); //5
}
scopetest2();
}
scopetest1();
对应的做用域范围
Scopetest3做用域链:scopetest3—> scopetest2—> scopetest1—> window
具体检索过程:对于直接定义在当前环境的test3,在当前环境检索到以后便再也不继续检索,对于定义在scopetest2的test2,如今scopetest3中检索是否认义test2,没有找到,往外部查找,即在scopetest2中查找,找到后匹配正确,检索结束。
Scopetest2做用域链:scopetest2—> scopetest1—> window
具体检索过程:对于test2直接检索到,对于test3,因为scopetest1以及全局环境中都没有,因此检索失败,返回not defined。
Scopetest1做用域链:scopetest1—> window
具体检索过程:对于test1直接检索到,检索结束。
注意:
1、声明一个变量时省略了var 关键字的时候,因为浏览器解析时的容错机制,会将此变量加入全局环境(严格模式下会报错)。
将上边代码作稍微的改动:
function scopetest2() {
var test2 = 2; //可访问test1以及test2
function scopetest3() {
//省略
}
scopetest3();
test3 = 5;
console.log(test3); //5
}
scopetest2();
这个时候控制台输出并无报错,而是在初始化的时候把test3加入了全局环境,这个时候全局环境和scopetest3中都有了test3变量,其效果至关于:
var test3;
function scopetest1() {
var test1 = 1; //可访问test1
function scopetest2() {
var test2 = 2; //可访问test1以及test2
function scopetest3() {
//省略
}
scopetest3();
test3 = 5;
console.log(test3); //5
}
scopetest2();
}
scopetest1();
此时scopetest3中定义的test3的值依然是3。
二、当分别在不一样环境中声明同名变量时,离当前环境最近的变量将会覆盖其余环境定义的变量,以下:
function scopetest1() {
var test1 = 1;
var test2 = 2;
function scopetest2() {
var test1;
var test2 = 3;
console.log(test1+" "+test2); //undefined 3
}
scopetest2();
console.log(test1+" "+test2); //1 2
}
scopetest1();
这里scopetest2里test1只进行了声明而没有进行初始化,可是依旧覆盖了scopetest1中进行初始化的test1。
三、无块级做用域
以前经常会把块级做用域与函数的执行环境弄混淆,在这里区别一下。
function mytest2 (){
var i;
for(i=0;i<10;i++){
var j = i;
}
console.log("结束循环"+j); //控制台输出9
}
mytest2();
在for中定义的变量j在花括号以外依旧存在,其变量是加入到最近的环境中的,在js中if while等都没有块级做用域,本身定义的函数都具备本身的执行环境,即做用域。能够经过匿名函数来模仿块级做用域。