1.JavaScript作用域与作用域链
<1>声明提前:1>
JavaScript函数里声明的所有变量都被提前至函数体的顶部。示例:
1 2 3 4 5 6 7 8 9
| var scope="global"; function fun(){ console.log(scope); var scope="local" console.log(scope); } undefined local
|
由于声明提前,fun()内的变量scope的声明相当于被提前到fun()的最前面,但此时没有被初始化,所以第一个log打印出的是“undefined”。
<2>全局对象属性:2>
JavaScript中,没有用var声明的变量都是全局变量,而且是顶层对象的属性。示例:
1 2 3 4 5 6 7 8 9 10 11 12 13
| function fun(){ if(true){ s="ifscope"; for(var i=0;i<2;i++); } console.log(i); } fun(); console.log(s); 2 ifscope
|
虽然s是在fun()中定义的,但离开了fun()的作用域s仍然可用,因为s是顶层对象的属性。
<3>作用域链3>
作用域链是一个对象列表或者链表,这组对象定义了这段代码“作用域中”的变量,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| function a(){ var name = "a"; function b(){ var name = "b"; console.log(name); } function c(){ var name = "c"; console.log(name); } b(); c(); console.log(name); } a(); b c a
|
在运行b()时,作用域链是b()->a()->全局
2.with语句
with语句将对象添加到作用域链的头部,然后执行一个代码块,离开代码块时作用域恢复到原来的状态。
在对象嵌套层次很深的时候通常会使用with语句类简化代码编写,例如:
1 2 3
| document.forms[0].name.value = ""; document.forms[0].address.value = ""; document.forms[0].email.value = "";
|
可以写成:
1 2 3 4 5
| with(document.forms[0]){ name.value = ""; address.value = ""; email.value = ""; }
|
这种方法减少了大量的输入。当然,不适用with语句的等价代码也可以是:
1 2 3 4
| var f = document.forms[0]; f.name.value = ""; f.address.value = ""; f.email.value = "";
|
with语句注意点:
若尝试将obj添加到作用域链头部并创建新的属性:
若对象obj有一个属性x,那么这行代码给这个属性赋值为1,若obj中没有属性x,这段代码和不适用with语句的代码x=1是一模一样的。可见,with语句提供了一种读取obj属性的快捷方式,但不能创建obj的属性。