`

JavaScript作用域链

阅读更多

作用域是程序开发的一个重要的部分。
      javascript 程序的每一个字节都是在这个或那个运行上下文(execution context)中执行的。你可以把这些上下文想象为代码的邻居,它们可以给每一行代码指明:从何处来,朋友和邻居又是谁。没错,这是很重要的信息,因为 javascript社会有相当严格的规则,规定谁可以跟谁交往,我们通常可以把这些社会边界称为作用域。并且有充足的重要性在每一位邻居的宪章里立法,而这个宪章就是我们要说的上下文的作用域链(scope chain)【摘抄,写的挺形象】。
    理解JavaScript作用域链首选的知道javascript一些JavaScript的运行机制

    (1)JavaScript是先编译再执行【并且是边编译边执行】
     编译期对所有的变量和函数处理,注意:变量处理只为变量的声明,而没有赋值,所有再编译期时无法分别是否提示变量是否已初始化。
     执行时JavaScript解释器按代码逻辑从上到下依次执行,如果变量没有初始化则为undefined。
    (2)JavaScript与html一样都是从上到下依次执行
    (3)JavaScript是按script块编译。 即解释器时在加载完毕<script  language="JavaScript" type="text/javascript"> </script> 的</script> 标签是才编译因此在<script>中直接使用下个<script>中的函数或者变量时,会提示undefined;
     所说JavaScript是按<script>块执行,但对应块中的函数及变量都属于同一作用域window。
    (4)JavaScript中只有函数有作用域,而对于if、for、while、switch等块结构是没有作用域的
其他还有很多这里就不一一列举了,以上四条条主要是在后面讲解JavaScript域链有作用,如果就想更深一步的了解JavaScript的运行机制可以看看书籍的<<javascript征途>>第一章讲的挺好的,我也是从里面才知道前面的四条。JavaScript作用域机制
     javascript的作用域机制:词法作用域(lexcical scope)。通俗地讲,就是javascript变量的作用域是在定义时决定而不是执行时决定,也就是说词法作用域取决于源码,编译器通过静态分析就能确定,因此词法作用域也叫做静态作用域(static scope)。但需要注意,with和eval的语义无法仅通过静态技术实现,所以只能说javascript的作用域机制非常接近词法作用域(lexical scope)。javascript引擎在执行每个函数实例时,都会创建一个执行环境(execution context)。执行环境中包含一个调用对象(call object), 调用对象是一个scriptObject结构(scriptObject是 与函数相关的一套静态系统,与函数实例的生命周期保持一致),用来保存内部变量表varDecls、内嵌函数表funDecls、父级引用列表 upvalue等语法分析结构(注意varDecls和funDecls等信息是在语法分析阶段就已经得到,并保存在语法树中。函数实例执行时,会将这些 信息从语法树复制到scriptObject上)。
      词法作用域(lexical scope)它的实现方法,就是作用域链(scope chain)。作用域链是一个name lookup机制,首先在当前执行环境的scriptObject中寻找,没找到,则顺着upvalue到父scriptObject中寻找,一直lookup到全局调用对象(global object)。 【这段也是摘抄的后面将结合实例介绍该作用域机制】;

换句话说“JavaScript中的函数运行在它们被定义的作用域里,而不是它们被执行的作用域里”。

JavaScript作用域分为两类
全局作用域window及函数调用作用域
全局作用域只存在唯一的一个及widows作用域,函数作用域可以嵌套函数作用域。
哪些变量具有函数的作用域呢,哪些是具有全局的作用域?
函数作用域就简单提一下,函数中使用var声明的变量和函数都是函数作用域当中。
JavaScript全局的作用域主要包含三类:
一:window对象的属性或函数。
 示例一

 <script  language="JavaScript" type="text/javascript">
   window.wVar = "wVar";//wVar window对象的属性具有全局作用域
  function getWvar(){
   alert( wVar );//弹出wVar
  }
  getWvar();
  </script>

       
二:<script>中直接定义的变量。
        示例二

 <script  language="JavaScript" type="text/javascript">
   var wVar = "wVar";//在<script>声明的变量都具有window作用域
  //wVar = "wVar";//该方式声明已可以
  function getWvar(){
   alert( wVar );//弹出wVar
  alert( window.wVar );//弹出wVar,全局变量即为window的属性
  }
  getWvar();
 </script>

 

三:函数中未带var修饰符的变量。
     示例三

  <script  language="JavaScript" type="text/javascript">
  function setWvar(){
   wVar = "wVar";//未加var 修饰符为全局变量 
 }
  function getWvar(){
   alert( wVar );//弹出wVar
  alert( window.wVar );//弹出wVar,全局变量即为window的属性
  }
  setWvar();
  getWvar();
  </script>
  <script  language="JavaScript" type="text/javascript">
  function setWvar(){
   var wVar = "wVar";//加var 为setWvar域的局部变量
 }
  function getWvar(){
   alert( wVar );//出错提示未定义
  }
  setWvar();
  getWvar();
   </script>

 

注意,为什么window域的属性能在函数中使用,这就是JavaScript作用域机制造成的,预编译函数会创建作用域【scope】,并在调用该函数时将该作用域链接到,已有的作用域链的最前端。示例二中,预编译函数getWvar时,将创建getWvar的作用域,
[[scope]] = [
{
}
]
调用函数getWvar,将该作用域链接到已有作用域链的最前端,此时作用域链为 getWvar->window,
[[scope chain]] = [

}, {
 //window
 wVar  : 'laruence'
}
]
当getWvar使用wVar变量时先会在getWvar函数作用域中查找是否存在变量wVar的定义,它没有查询到,就会作用域链的上级window域查找变量wVar,能查询到所以弹出值wVar。如果getWvar函数中存在变量wVar的定义,则在函数变量wVar会屏蔽window域同名的变量。总结来说"调用对象位于作用域链的前端,局部变量(在函数内部用var声明的变量)、函数参数及Arguments对象都在函数内的作用域中——这意味着它们隐藏了作用域链更上层的任何同名的属性。";。

会有人问函数调用是否会造成作用域链嵌套,请看如下示例。

 <script  language="JavaScript" type="text/javascript">
 function setWvar(){
   var wVar = "wVar";
  getWvar();
 }
 function getWvar(){
   alert( wVar );
 }
 setWvar();
     </script>

  

示例中的的setWvar();执行结果会怎样,是否值为wVar,答案是错误的。实际值为undefine;
这个怎么会这样呢,不时按照作用域链来说getWvar->setWvar->window结构如下
[[scope chain]] = [
{
  //getWvar scope
  wVar = undefine 
},
{
 //setWvar scope
 wVar="wVar" 
}, {
 //window
}
]
以上理解是错误的,JavaScript作用域中最重要的是“JavaScript中的函数运行在它们被定义的作用域里,而不是它们被执行的作用域里”;
getWvar是在script中定义,所以调用它时,它的作用域链为
[[scope chain]] = [
{
  //getWvar scope
  wVar = undefine 
},
{
 //window
}
]
同样对于setWvar()来说也是在script中定义,所以调用它时,它的作用域链为
[[scope chain]] = [
{
  //setWvar scope
  wVar = undefine 
},
{
 //window
}
]
并不因为调用关系而将作用域链接在一起。
所以调用函数setWvar时,getWvar的作用域也仅仅是getWvar定义是的作用域,而不时它执行的作用域。
那如下情况呢

<script  language="JavaScript" type="text/javascript">
 function setWvar(){ 
  function getWvar(){
    alert( wVar );
  }
  var wVar = "wVar";
  getWvar();
 }
 setWvar();
     </script>

   

结果为值wVar,怎么和上面的结果不一样,这里你要特别的注意到,getWvar()被定义在setWvar函数里面的所以getWvar函数的作用链为
[[scope chain]] = [
{
  //getWvar scope
  wVar = undefine 
},
{
 //setWvar scope
 wVar="wVar" 
}, {
 //window scope
}
]
这样你就能看到为什么值为wVar【这也是JavaScript闭包的应用】。

再看如下示例
  

   <script  language="JavaScript" type="text/javascript">
 wVar = "window"
 function setWvar(){
  alert( wVar ); //1
  var wVar = "wVar";
  alert( wVar ); //2 
 }
 setWvar();
     </script>

 

猜猜会是什么结果是否1弹出window,2弹出的wVar。
真正的结果是1为undefined,2为wVar。
我们从作用域链解释为什么会这样,首先wVar定义在setWvar中所以setWvar应该处于setWvar的scope中【上面提到的第四条,只有函数存在作用域,编译时就已经确定局部变量wVar作用域时setWvar】,所以它会覆盖window scope中wVar 的值。而当执行到1时,此时局部变量wVar并未赋值,所以系统化给出初始值为undefined。而执行到2时,此时局部变量已赋值为wVar,所以2弹出wVar;
上面的示例代码等价于
  

  <script  language="JavaScript" type="text/javascript">
 wVar = "window"
 function setWvar(){
  var wVar;
  alert( wVar ); //1
  wVar = "wVar";
  alert( wVar ); //2 
 }
 setWvar();
     </script>

 

要理解这些示例,请一定要理解前面讲到的JavaScript运行机制,及词法作用域。
函数作用域链就写到这里,以后再补充作用域与闭包,
参考
http://www.laruence.com/2009/05/28/863.html
http://www.cnblogs.com/hhyy329/archive/2009/08/20/1550827.html

分享到:
评论
3 楼 80197675 2011-12-28  
ncx1259988 写道
[[scope chain]] = [
{
  //getWvar scope
  wVar = undefine
},
{
//window
}
]
同样对于setWvar()来说也是在script中定义,所以调用它时,它的作用域链为
[[scope chain]] = [
{
  //setWvar scope
  wVar = undefine //这里为什么是undefine啊
},
{
//window
}
]

javascript函数作用域是和 函数声明的位置有关,和调用位置无关,相关的作用域链与调用位置无关,只有声明位置相关。
所以虽然 setWvar()调用了getWvar();
但getWvar()作用域链为
[[scope chain]] = [
{
  //getWvar scope
},
{
//window
}
]
而不是
[[scope chain]] = [
{
  //getWvar scope
},
{
  //setWvar scope
  wVar = "wVar";
},

{
//window
}
]
所以你使用setWvar()的调用getWvar,变量wVar  对于getWvar 是不可见的 所有
是undefined

2 楼 ncx1259988 2011-12-28  
[[scope chain]] = [
{
  //getWvar scope
  wVar = undefine
},
{
//window
}
]
同样对于setWvar()来说也是在script中定义,所以调用它时,它的作用域链为
[[scope chain]] = [
{
  //setWvar scope
  wVar = undefine //这里为什么是undefine啊
},
{
//window
}
]
1 楼 ncx1259988 2011-12-28  
请教一下下面的这个例子
1.<script  language="JavaScript" type="text/javascript">  
2.function setWvar(){  
3.  var wVar = "wVar";  
4. getWvar();  
5.}  
6.function getWvar(){  
7.  alert( wVar );  
8.}  
9.setWvar();  
10.    </script>

相关推荐

    javascript作用域链(Scope Chain)初探.docx

    ### JavaScript作用域链(Scope Chain)初探 #### 一、引言 JavaScript的作用域链是一个重要的概念,尤其是在深入理解JavaScript执行机制时不可或缺的一部分。本文将通过对几个具体例子的分析来探讨JavaScript作用域...

    scope-chains-closures, Javascript作用域链和闭包 workshop.zip

    scope-chains-closures, Javascript作用域链和闭包 workshop 范围链和闭包 workshop正在启动$ npm install -g scope-chains-closures$ scope-chains-closures # or, shorter: sccjs使用箭头

    javascript作用域链(Scope Chain)用法实例解析

    JavaScript 作用域链是 JavaScript 语言中一个至关重要的概念,它决定了变量和函数的访问权限。在 JavaScript 中,每个函数都有自己的作用域,也就是变量和函数的可见范围。当一个函数被创建时,它会形成一个作用域...

    深入理解JavaScript作用域和作用域链

    深入理解JavaScript作用域和作用域链对于编写高效、无错的代码至关重要。正确管理作用域可以避免全局变量冲突,提高代码的复用性和模块化,同时也有助于提升性能,因为局部变量的访问速度通常比全局变量快。在实际...

    JavaScript 作用域链解析

    在深入探讨JavaScript作用域链解析之前,首先需要明确几个关键概念:作用域(Scope)、作用域链(Scopechain)、执行上下文(Executecontext)、活动对象(ActiveObject)、动态作用域(Dynamic Scope)以及闭包...

    JavaScript作用域链示例分享

    JavaScript作用域链是编程语言中一个关键的概念,它在JavaScript中扮演着至关重要的角色,尤其对于变量的查找和管理有着深远的影响。理解作用域链有助于我们编写更清晰、更安全的代码,避免出现意外的变量污染和作用...

    JavaScript作用域链实例详解

    JavaScript作用域链是JavaScript语言中一个关键的概念,它关乎变量和函数查找的顺序以及作用域内的数据访问。本文将深入探讨这一主题,并结合实例进行详细解释。 首先,我们需要理解作用域的基本概念。在JavaScript...

    JavaScript作用域链使用介绍

    在深入探讨JavaScript作用域链之前,首先需要了解作用域的概念。在编程语言中,作用域定义了变量和函数的可访问范围,即这些变量和函数在哪些区域中可见,以及它们的生命周期如何。JavaScript中的作用域分为两种:...

    浅析JavaScript作用域链、执行上下文与闭包

    JavaScript 采用词法作用域(lexical scoping),函数执行依赖的变量作用域是由函数定义的时候决定,而不是函数执行的时候决定,通过本文给大家介绍JavaScript作用域链、执行上下文与闭包相关知识,感兴趣的朋友一起...

    图解javascript作用域链

    JavaScript的作用域链是理解JavaScript执行环境的关键概念,它决定了变量和函数的可访问性。在JavaScript中,每个函数都有自己的作用域,而这些作用域按照特定的顺序组织起来,形成了作用域链。这个链帮助解析器在...

    JavaScript中作用域链的概念及用途讲解

    JavaScript中的作用域链是编程中一个至关重要的概念,它决定了变量和函数的可访问性以及在不同作用域内的查找顺序。在深入理解作用域链之前,我们首先要了解什么是执行环境和变量对象。 执行环境,简单来说,就是...

    关于Javascript作用域链的八点总结

    JavaScript的作用域链是理解JavaScript变量查找和闭包的关键概念。以下是对这八个点的详细解释: 1. **定义时作用域链与运行时作用域链**: - 定义时作用域链([[Scope]])是在函数创建时确定的,它记录了函数声明...

    理解JavaScript作用域和作用域链

    作用域是JavaScript最重要的概念之一,想要学好JavaScript就需要理解JavaScript作用域和作用域链的工作原理。今天这篇文章对JavaScript作用域和作用域链作简单的介绍,希望能帮助大家更好的学习JavaScript。任何程序...

    javascript变量作用域

    JavaScript 变量作用域是基于其特有的作用域链的。在 JavaScript 中,变量作用域是指变量可以被访问和修改的范围。 JavaScript 没有块级作用域,而是基于函数作用域和全局作用域的。 首先,看看 JavaScript 的作用...

Global site tag (gtag.js) - Google Analytics