一、作用域
1.定义:变量在声明他们的函数体以及这个函数体嵌套的任何的函数体内都是有定义的。
<script type="text/javascript">
var a = 10;
function num1(){
var b = 20;
(function num2(){
console.log(a); //10
console.log(b); //20
})();
}
num1();
console.log(a); //10
console.log(b); //报错
</script>
结论:a在全局中以及他所嵌套的所有函数中是有定于的,b在函数num1以及他所嵌套的所有函数是有定于的。
-
因此a的作用域是全局,b的作用域是声明他的函数。
2.函数作用域
- 在JavaScript中变量的作用域,在变量声明的代码段之外是不可见的。上述代码中num1 就是一个函数作用域。
- 注意:在函数体中定义变量必须使用var,否则该变量为全局变量。
<script type="text/javascript">
function num(){
a = 10;
}
num();
console.log(a); //10
</script>
3.if,while,for
- 在javascript中,if、while、for 等代码块不能形成独立的作用域。因此,javascript中没有块级作用域,只有函数作用域。
<script type="text/javascript">
for(var i=0;i<10;i++){
var a = 10;
}
while(1){
var b = 20;
break;
}
if(1){
var c = 30;
}
console.log(a); //10
console.log(b); //20
console.log(c); //30
</script>
二、作用域链
1.定义:
一个函数体中嵌套了多层函数体,并在不同的函数体中定义了同一变量, 当其中一个函数访问这个变量时,便会形成一条作用域链。
2.
<script type="text/javascript">
foo = "window";
function first(){
var foo = "first";
function second(){
var foo = "second";
console.log(foo);
}
function third(){
console.log(foo);
}
second(); //second
third(); //first
}
first();
</script>
3.结论:
- 在执行second();时,JS引擎会将second的作用域放置链表的头部,其次是first的作用域,最后是window对象,于是会形成如下作用域链:second->first->window,因此foo = "second";
- 同理,在执行third();时,会形成如下作用域链:third->first->window,因此foo = "first";
三、延长作用域链
1.with 和 catch 语句主要用来临时扩展作用域链, 将语句中传递的变量对象添加到作用域的头部。语句结束后,原作用域链恢复正常。
2.
<script type="text/javascript">
//with语句
foo = "window";
function first(){
var foo = "first";
function second(){
var foo = "second";
console.log(foo);
}
function third(obj){
console.log(foo); //first
with (obj){
console.log(foo); //obj
}
console.log(foo); //first
}
var obj = {foo:'obj'};
third(obj);
}
first();
//catch语句
var e = new Error('a');
try {
throw new Error('b');
} catch (e) {
console.log(e.message); //b
}
</script>
3.结论:
(1)在执行third()时,传递了一个obj对象,obj 中有属性foo, 在执行with语句时,JS引擎将obj放置在了原链表的头部,于是形成的作用域链如下:obj->third->first->window,因此输出的是 obj
(2)在with之前和之后,都是沿着原来的链表进行查找,从而说明在with语句结束后,作用域链已恢复正常。
网友评论