谁动了我的代码

抽象即是空,空即是抽象。
posts(43) comments(24) trackbacks(0)
  • BlogJava
  • 联系
  • RSS 2.0 Feed 聚合
  • 管理

News

所有文章版权归我所有,转载请注明出处,谢谢!

常用链接

  • 我的随笔
  • 我的评论
  • 我的参与
  • 最新评论

留言簿

  • 给我留言
  • 查看公开留言
  • 查看私人留言

随笔分类

  • Android开发(5)
  • C/C++(1)
  • DataBase(3)
  • Java(16)
  • JavaScript(14)
  • WEB前端(1)
  • 编程杂项(2)
  • 网络(1)

随笔档案

  • 2016年5月 (1)
  • 2011年2月 (1)
  • 2010年6月 (3)
  • 2010年5月 (1)
  • 2009年12月 (2)
  • 2009年11月 (1)
  • 2009年10月 (2)
  • 2009年6月 (2)
  • 2009年5月 (1)
  • 2009年4月 (2)
  • 2009年3月 (4)
  • 2009年2月 (1)
  • 2009年1月 (1)
  • 2008年12月 (1)
  • 2008年11月 (1)
  • 2008年10月 (4)
  • 2008年9月 (2)
  • 2008年5月 (5)
  • 2008年3月 (3)
  • 2007年12月 (2)
  • 2007年10月 (1)
  • 2007年9月 (2)
  • 2007年5月 (1)

搜索

  •  

最新评论

  • 1. re: Android之ImageView载入网络上的图片
  • 222222222222222222222
  • --2222222222222222222222222222
  • 2. re: Log4j自带Log Viewer的用法
  • 执行你的根本不行,乱错帖子就在这乱贴,tmd
  • --asdf
  • 3. re: Android之使用私有存储
  • getDir方法创建的文件,会有个app_前缀,请问这怎么去掉呢?
  • --就是宝宝
  • 4. re: Android通用事件造成的生命周期变化情况
  • 我相信以后Android将成为越来越多设备的OS,不光是手持上网设置,冰箱、洗衣机都有可能采用Android。
  • --淘宝网女装春装新款
  • 5. re: Android通用事件造成的生命周期变化情况
  • 不错
  • --歌瑞尔内衣

阅读排行榜

评论排行榜

View Post

对JavaScript的变量作用域的理解

作用域是一个抽象概念,在浏览器的JavaScript实现中会有这个概念,但是不同浏览器实现可能不同。

一、作用域的种类(自己感悟)
1.对象作用域,window及标签元素都属于对象作用域。
2.函数作用域,函数自身形成的作用域。
可以把作用域看作是上下文(context)之类的对象。

看下面的代码
例0

 1breakE = 0;
 2var state = 1;                //1
 3Person = function(name) {     //2
 4    var age = 20;
 5    this.name = name;
 6    this.show = function () {     //3
 7        alert(age);
 8        alert(state);
 9        alert(name);
               alert(
this.name);
10    }

11    alert(m);
12}

13    Person.prototype.check = function () {};
14m = new Person('mike');       //4
15var j = new Person('Jerry');      //5
16
17m.show();                     //6
通过看上面这段代码我们发现有时候定义变量时用var,有时候却不用,这里有什么区别吗?在此之前我们先定下规矩,那就是必须有一个全局作用域,就像是window对象的存在一样,是作用域的最顶层。那么哪些变量被定义到作用域的最顶层呢?那就是state,对于不在任何函数或类中用var定义的变量存在于全局作用域中。那么全局作用域属于作用域的哪种类型呢?那就是对象作用域。具体是哪个对象的作用域呢?非window对象莫属。

我们可以把对象作用域想像成两部分,左面部分是对象级别的,保存的是和对象绑定的成员属性(无论是变量还是函数),通过this来访问的。右面的部分是作用域级别的,保存的是var定义的属性(无论是变量还是函数),可以直接通过变量名称访问。对于window来说它是个特殊体,从用var定义的变量可以用this来访问就能看出问题,我个人猜测window对象既是JavaScript的顶层对象又是顶层作用域,所以才会有这种效果。
另一种情况就是标签元素的对象作用域和全局作用域非常的像,如下例:
 1//例1
 2<input type='button' value='click me' onclick='alert(value)'/>
 3//例2
 4<input type='button' value='click me' onclick='alert(this.value)'/>
 5//例3
 6function test() {
 7    alert(value);
 8    alert(this.value);
 9}

10<input type='button' value='click me' onclick='test()'/>
很奇怪为什么例1和例2访问value和全局作用域里的var定义的变量的行为是一致的,按理说value应该属于input标签元素对象的成员属性,访问对象的成员属性应该用this来访问,我们自定义的类,如果成员方法想访问成员变量都需要加this的,就像最上面的例子里的this.show方法访问this.name成员变量一样。而对于例3,勤快的读者如果运行一下便知一定会出错的,第一句系统会报value未定义(除非你在全局作用域定义过value变量),第二句会打印出undefined。为什么会这样呢?这就要引出作用域链这个概念了,后面会解释这个概念的。

反观函数作用域,由于函数中用var定义的变量不能用this来访问,所以在函数作用域中不再像对象作用域那样分两部分,而this实际保存的是与该函数绑定的对象的引用,也就是说this在函数中有特殊的含义,是不能挪作它用的。

二、作用域链
作用域是可以嵌套的,而嵌套的结果就形成了作用域链,如例0所示,我们来描述一下作用域链:
全局作用域<----Person函数作用域<-----show函数作用域
在全局作用域中可以访问哪些变量呢(注意我现在指的只是作用域中的变量)?
1.state
2.j
在Person函数作用域中可以访问哪些变量呢?
1.全局作用域中的所有可访问的变量
2.name(参数)
3.age
在show函数中又有哪些变量可以被访问呢?
1.全局作用域中的所有可访问变量
2.Person函数作用域中所有可访问变量
3.如若show函数中还定义了var变量也要加入show函数作用域

如果在show中访问一个x变量,首先从show函数作用域里查是否有x这个变量,如果没有再查Person作用域,如果还没有的话再查全局作用域,找到就返回该变量。
讲解到这里我们发现一个问题,似乎作用域是定义时生成块级作用域(即单独的对象作用域和函数作用域)而运行时生成作用域链,这就是词法作用域的由来。有了这种作用域就构成了闭包的基础。
下面是一个稍微特殊的例子:
 1 function test() {
 2     test2();
 3 }
 4 
 5 function test3() {
 6     test2 = function() {
 7         alert("test2");
 8     }
 9     test();
10 }
定义test的时候test2还不存在,但是调用test的时候,test2就存在了,这说明了作用域链确实是运行时生成的。

通过作用域链如何解释例1、2、3呢?
我的分析是对于HTML元素来说当页面解析的时候,元素被解析成DOM树,HTML元素里的标准属性作为该元素对象作用域的变量(类似var定义的那种),而非该元素DOM对象的成员属性(类似this定义的那种),这样就解释了两个问题:
1.在页面上预定义的HTML元素标准属性是不能用delete和removeAttribute删除的。
2.onclick属于input元素的一个方法,那么这个作用域链应该像下面这样:
   全局作用域<-----HTML元素作用域<-------onclick函数作用域
   value变量在哪个作用域里呢?答案是HTML元素作用域中。所以onclick不但可以访问而且加不加this都可以。
那么例3的作用域链是什么样的呢?如下:
    全局作用域<-----test函数作用域
    全局作用域<-----HTML元素作用域<-------onclick函数作用域
没错是两条,因为当单击按钮后执行到onclick函数中时走的是第二条链,而在onclick中调用了test函数时,走的是第一条链。
显然value还是定义在HTML元素作用域中,而test想访问value值一定是访问不到的。

对于这个问题我还测试了一下非标准属性,如下例:
1<input type="button" value="click me" bb="123" onclick="delete this.bb; alert(bb)"/>
测试发现非标准的HTML元素属性可以被删除,但是delete语句执行时必须用this来引用(IE中测试),直接访问如alert到没有这个限制。
说明bb是input对象属性是没错的,因为它可以被删除,但是如果它没有被删除的话alert(bb)还是能显示出来的,说明这类属性很特殊,具体怎么解释我还没有想好,如果有朋友能解释的通,请告知我。

三、什么是闭包
show函数显然是一个闭包,但是它是由类的构造函数生成的,和另一种形式其实是一样的,代码如下:
 1function getFunc (a, b) {
 2    return function () {
 3         alert(a - b);
 4    }

 5}
 
 6
 7var func1 = getFunc(10,5);
 8func1();
 9
10var func2 = getFunc(20,30);
11func2();
上面的代码func1函数无论我执行多少次都显示5,func2函数无论我执行多少次都显示-10,这和例0是多么的像呀,例0中m.show()无论执行多少次都能显示'mike',j.show()无论执行多少次都能显示'Jerry'(行号9那行在起作用,先不考虑this.name那行)。这就是闭包,把作用域链中变化的变量给固定化,然后把作用域链和函数本身进行绑定,无论我在什么地方执行函数,函数的作用域链始终是它定义的时候那条。

四、关于对象成员的访问(即this能引用的那些属性),我只是在猜想,可能的作用域链应该如下:
    全局作用域<-------m对象作用域<-------m.test函数作用域
    m的对象成员(类中this定义的)保存在对象作用域的左半部,m的作用域变量(类中var定义的)保存在对象作用域的右半部。
    m.test函数要访问对象成员时从对象作用域的左半部检索,要访问作用域变量时从对象作用域的右半部检索。
    同时这个作用域链还解答了另一个问题,即原型方法(公共方法)为什么不能访问类中用var定义的变量。
    看例0即可知check和Person根本就不在同一个链上,又谈何能访问呢?

至此把JavaScript变量作用域讲解完毕,我觉得这个还是蛮重要的,如果一定要有个比较的话,应该和Java中的ClassLoader有同样的重要性吧。大家借鉴的同时请多给我指出错误,因为这其中有一些还是我的猜测。

posted on 2009-05-19 02:06 Eric Song 阅读(512) 评论(0)  编辑  收藏 所属分类: JavaScript

新用户注册  刷新评论列表  

只有注册用户登录后才能发表评论。


网站导航:
博客园   IT新闻   Chat2DB   C++博客   博问   管理
相关文章:
  • 关于样式表对象style与currentStyle的区别
  • 关于JavaScript的cloneNode方法对于节点上的事件clone问题的研究。
  • 参考Prototype的Class.create写了一个类似的实现,但是不是Ruby like OOP,使用上更像Java。
  • 对JavaScript的变量作用域的理解
  • IE document compatMode
  • JavaScript对form及form中的引用。
  • JavaScript注意事项(不定期更新)
  • 在定义一个js类的时候,为什么要设置该类的prototype属性为它所要继承的类的实例对象
  • JavaScript 类型转换注意事项
  • 面向对象的JavaScript(二,TSS上的一篇文章,先借鉴一下)
 
 
Powered by:
BlogJava
Copyright © Eric Song