现在的位置: 首页 > 综合 > 正文

Javascript作用域浅析

2018年05月04日 ⁄ 综合 ⁄ 共 4945字 ⁄ 字号 评论关闭

 学习任何编程语言,都逃不过理解变量的作用域。

在javascript中,变量的作用域有全局(window对象)作用域和函数调用作用域。

以下变量具有全局作用域
1. 所有在最外层定义(非函数体内定义)的变量都拥有全局作用域
2. 所有末定义直接赋值的变量,系统会自动声明为拥有全局作用域的变量
3. 所有window对象的属性拥有全局作用域

以下变量具有函数作用域
1. 在函数体内部用var定义的变量,这里要注意一点,只要是在函数里定义的变量,就算是在最后一句定义,该变量也拥有整个函数的作用域。

特别应该说明的一点是,作用域是层层包含的,最外层是全局作用域,里面可以包含函数调用作用域,函数调用作用域里面还可以再有函数作用域,下面,我们看一个简单的例子:

<mce:script type="text/javascript"><!--  
var scope = "global";  
window.x = "x-global";  
 
var f1 = function(){  
    var scope = "function1";  
    y = "y-golbal";  
    alert(scope);    //will display function1  
    alert(window.scope);  //will display global  
    alert(x);               //will display x-global  
}  
 
f1();  
 
alert(scope);//will display global  
alert(y);    //will display y-golbal  
// --></mce:script> 
<mce:script type="text/javascript"><!--
var scope = "global";
window.x = "x-global";

var f1 = function(){
 var scope = "function1";
 y = "y-golbal";
 alert(scope);    //will display function1
 alert(window.scope);  //will display global
 alert(x);               //will display x-global
}

f1();

alert(scope);//will display global
alert(y);    //will display y-golbal
// --></mce:script>
 

这个例子说明了简单的全局作用域和函数作用域的区别,我们再思考一下问题,如果函数f1里面没有变量scope,而全局作用域里面有这个变量,会有什么情况呢?

view plaincopy to clipboardprint?
<mce:script type="text/javascript"><!--  
var scope = "global";  
 
var f1 = function(){  
    //var scope = "function1";  
    alert(scope);    //will display global  
    alert(window.scope);  //will display global  
      
}  
 
f1();  
 
alert(scope);//will display global  
// --></mce:script> 
<mce:script type="text/javascript"><!--
var scope = "global";

var f1 = function(){
 //var scope = "function1";
 alert(scope);    //will display global
 alert(window.scope);  //will display global
 
}

f1();

alert(scope);//will display global
// --></mce:script>
 

为什么会这样呢,这是由于javascript的寻找变量的机制造成的。上面己经说了,作用域是层层包含的,上面的这个例子的层次应该是这样的: 全局作用域->f1的作用域。而javascript查找一个变量时,会从当前作用域往上找,直到找到为止,所以这个例子中,先在f1的作用域找scope,找不到,则到外层的全局作用域找,在全局作用域中找到了scope,就使用该变量,这个例子中,如果在全局作用域也找不到变量scope,则会报错。
下面我们把这个例子改一下,就会有一个很有趣的现象

view plaincopy to clipboardprint?
<mce:script type="text/javascript"><!--  
var scope = "global";  
 
var f1 = function(){  
      
    alert(scope);    //will display undefined  
    alert(this.scope);  //will display global  
    var scope = "function1";  //declare scope here  
}  
 
f1();  
 
alert(scope);//will display global  
// --></mce:script> 
<mce:script type="text/javascript"><!--
var scope = "global";

var f1 = function(){
 
 alert(scope);    //will display undefined
 alert(this.scope);  //will display global
 var scope = "function1";  //declare scope here
}

f1();

alert(scope);//will display global
// --></mce:script>
 

这里还是用javascript查找变量的机制来解释,首先在f1的作用域里面找,而f1定义了该变量,所以使用该变量,但是还末赋值,所以是undefined。这里要说明一点,就是作用域内的变量不管在函数的哪里声明,javascript都会在函数运行前在作用域内包含该变量。
下面,我们再看复杂一些的例子:

view plaincopy to clipboardprint?
<mce:script type="text/javascript"><!--  
var scope = "global";  
var scope2 = "global-scope2" 
 
var f1 = function(){  
    var scope = "function1";  
    var scope2 = "function1-scope2";  
    (function(){ //function2  
        var scope = "function2";  
        (function(){  //function3  
            alert(scope);  //will display function2  
            alert(scope2);  //will display function1-scope2  
        })();  
          
    })();  
      
      
}  
 
f1();  
// --></mce:script> 
<mce:script type="text/javascript"><!--
var scope = "global";
var scope2 = "global-scope2"

var f1 = function(){
 var scope = "function1";
 var scope2 = "function1-scope2";
 (function(){ //function2
  var scope = "function2";
  (function(){  //function3
   alert(scope);  //will display function2
   alert(scope2);  //will display function1-scope2
  })();
  
 })();
 
 
}

f1();
// --></mce:script>
 

下面,我们还是以javascript查找变量的机制来解释一下。首先,我们看看作用域的包含情况: 全局作用域-> f1的作用域 ->f2的作用域-> f3的作用域。对于变量scope,先在f3作用域内找,没找到,往外,在f2作用域里找到,使用该值,所以打出的值为 function2。对于scope2,先在f3找,没找到,住外,在f2找,还是没找到,再往外,在f1找,找到,使用该值,所以打出的值为function1-scope2。

上面的函数都是在定义该函数的作用域里调用,如f3 在f2定义并调用,f1在全局作用域里定义并在全局作用域调用,那么,如果在全局作用域调用,或是在别的函数里调用f3会有什么情况呢?下面我们试一下:

view plaincopy to clipboardprint?
<mce:script type="text/javascript"><!--  
var scope = "global";  
var scope2 = "global-scope2" 
 
var f1 = function(){  
    var scope = "function1";  
    var scope2 = "function1-scope2";  
    return (function(){  
        var scope = "function2";  
        return function(){  
            alert(scope);  //will display function2  
            alert(scope2);  //will display function1-scope2  
        }  
          
    })();  
      
      
}  
 
var f4 = function(fun)  
{  
    fun();  
}  
 
var f3 = f1();  
 
 
f4(f3);  
// --></mce:script> 
<mce:script type="text/javascript"><!--
var scope = "global";
var scope2 = "global-scope2"

var f1 = function(){
 var scope = "function1";
 var scope2 = "function1-scope2";
 return (function(){
  var scope = "function2";
  return function(){
   alert(scope);  //will display function2
   alert(scope2);  //will display function1-scope2
  }
  
 })();
 
 
}

var f4 = function(fun)
{
 fun();
}

var f3 = f1();

f4(f3);
// --></mce:script>
 

上面的例子我们返回f3,并在f4里面调用f3,但结果没变,为什么呢?这是因为javascript的作用域包含关系是在函数定义的时候确定的,而不是在调用的时候确定的,所以不管在哪调用f3,函数的作用域包含关系都是: 全局作用域->f1->f2->f3。不过上面的这个例子还有另外一个作用域包含关系: 全局作用域->f4的作用域。

最后,还要说明的是,javascript没有块作用域,这点跟java,c++,c#,php等都是不同的,所以在循环语句里面创建的变量也是拥有函数调用作用域或是全局作用域的,并不会有临时变量存在。

注:
1.在javascript里,函数也是可以作为数据传递的,在上面的例子里用到了函数作用数据传递
2.上面的例子用到了闭包的知识,不清楚的朋友可以了解一下相关的知识

 

抱歉!评论已关闭.