您的位置:首页 > 其它

深入理解函数的作用域

2017-03-03 21:31 218 查看
一、作用域(scope)

所谓作用域就是:变量在声明它们的函数体以及这个函数体嵌套的任意函数体内都是有定义的。

1 function scope(){
2     var foo = "global";
3     if(window.getComputedStyle){
4         var a = "I'm if";
5         console.log("if:"+foo); //if:global
6     }
7     while(1){
8         var b = "I'm while";
9         console.log("while:"+foo);//while:global
10         break;
11     }
12     !function (){
13         var c = "I'm function";
14         console.log("function:"+foo);//function:global
15     }();
16     console.log(
17          foo,//global
18          a, // I'm if
19          b, // I'm while
20          c  // c is not defined
21     );
22 }
23 scope();


(1)scope函数中定义的foo变量,除过自身可以访问以外,还可以在if语句、while语句和内嵌的匿名函数中访问。 因此,foo的作用域就是scope函数体。

(2)在javascript中,if、while、for 等代码块不能形成独立的作用域。因此,javascript中没有块级作用域,只有函数作用域。

 但是,在JS中有一种特殊情况:

 如果一个变量没有使用var声明,window便拥有了该属性,因此这个变量的作用域不属于某一个函数体,而是window对象。

1 function varscope(){
2     foo = "I'm in function";
3     console.log(foo);<
1048f
span style="margin:0px;padding:0px;color:rgb(0,128,0);line-height:1.5 !important;">//I'm in function
4 }
5 varscope();
6 console.log(window.foo); //I'm in function


二、作用域链(scope chain)

     所谓作用域链就是:一个函数体中嵌套了多层函数体,并在不同的函数体中定义了同一变量, 当其中一个函数访问这个变量时,便会形成一条作用域链(scope chain)。

1 foo = "window";
2 function first(){
3     var foo = "first";
4     function second(){
5        var foo = "second";
6        console.log(foo);
7     }
8     function third(){
9        console.log(foo);
10     }
11     second(); //second
12     third();  //first
13 }
14 first();


当执行second时,JS引擎会将second的作用域放置链表的头部,其次是first的作用域,最后是window对象,于是会形成如下作用域链:

second->first->window,  此时,JS引擎沿着该作用域链查找变量foo, 查到的是"second"

当执行third时,third形成的作用域链:third->first->window, 因此查到的是:"frist"

特殊情况:with语句

JS中的with语句主要用来临时扩展作用域链,将语句中的对象添加到作用域的头部。with语句结束后,作用域链恢复正常。

1 foo = "window";
2 function first(){
3     var foo = "first";
4     function second(){
5        var foo = "second";
6        console.log(foo);
7     }
8     function third(obj){
9        console.log(foo); //first
10        with (obj){
11            console.log(foo); //obj
12        }
13        console.log(foo); //first
14     }
15     var obj = {foo:'obj'};
16     third(obj);
17 }
18 first();


在执行third()时,传递了一个obj对象,obj中有属性foo, 在执行with语句时,JS引擎将obj放置在了原链表的头部,于是形成的作用域链如下:

obj->third->first->window, 此时查找到的foo就是obj中的foo,因此输出的是:"obj", 而在with之前和之后,都是沿着原来的链表进行查找,从而说明,在with语句结束后,作用域链已恢复正常。

三、this 关键字

     在一个函数中,this总是指向当前函数的所有者对象,this总是在运行时才能确定其具体的指向,
也才能知道它的调用对象。

     这句话总结了关于this的一切,切记,切记,切记!(ps:重要的事情说三遍!)

1 window.name = "window";
2 function f(){
3     console.log(this.name);
4 }
5 f();//window
6
7 var obj = {name:'obj'};
8 f.call(obj); //obj


在执行f()时,此时f()的调用者是window对象,因此输出"window"

f.call(obj) 是把f()放在obj对象上执行,相当于obj.f(),此时f中的this就是obj,所以输出的是"obj"

四、实战应用

code1:

1 var foo = "window";
2 var obj = {
3     foo : "obj",
4     getFoo : function(){
5         return function(){
6             return this.foo;
7         };
8     }
9 };
10 var f = obj.getFoo();
11 f(); //window


code2:

var foo = "window";
var obj = {
foo : "obj",
getFoo : function(){
var that = this;
return function(){
return that.foo;
};
}
};
var f = obj.getFoo();
f(); //obj
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: