网络编程
位置:首页>> 网络编程>> JavaScript>> Javascript Closures (1)

Javascript Closures (1)

作者:Dreamer 来源:Dreamer’s Blog 发布时间:2009-03-18 12:14:00 

标签:JavaScript,对象,作用域,闭包,closures

昨天又翻了下前段时间WD内部培训的幻灯片,发现了kejun推荐的一篇好文:Javascript Closures,看了之后受益匪浅。这篇文章不是简单地告诉你Javascipt 中的 closure 的好处和用法,而是从ECMAScript中的定义开始,帮助你从底层的机制和原理深入了解closure。了解了底层的机制之后你就不会单纯停留在使用的层面上,还会明白所有变量的初始化过程、作用域等,才算是真正掌握了closure。由于文章太长了,我就不翻译了,仅在此做一些笔记,仅供参考。另外,文中很多东西需要仔细琢磨一下,一下子总结出来对我来说比较吃力,所以决定分成几个部分来说,本文是第一部分。

原文:Javascript Closures

1.简介

闭包(closure) 是 JS 最强大的特性之一,简单地说,闭包就是内部方法,即定义在方法内的方法,它们可以访问外部方法内的变量和参数,即使外部方法的执行已经终止。例如:

function example(arg1){
  var localVar = 2;
  return function inner(arg2){
    return arg1+localVar + arg2;
  }
}

要了解闭包的内部机制不是一件简单的事情,有许多准备工作要做。我们先来看一下有关对象的一些东西。

2.对象和对象属性

在 JS 中一切都是对象,包括 function 。对象可能会有一些属性,这些属性的值可能是另外一个对象,也可能是原生的数据类型:String, Number, Boolean, Null 或者 Undefined 。下面我们来看一下给对象属性赋值和读取对象属性的原理。

var o = new Object();
o.testNumber = 5;

上面的代码中我们先是创建了一个对象 o ,然后对其属性 testNumber 赋值。请注意,一开始的时候对象o是没有 testNumber 这个属性的,所以当赋值的时候 JS 会先检查,发现没有这个属性就先创建这个属性,然后再对其进行赋值。如果这个时候再执行下面的代码:

o.testNumber = 8;

JS 同样会先检查对象o ,发现它有testNumber这个属性之后,就不会再创建该属性,而是直接重新设置它的值。下面看一下读取对象属性:


o.testNumber = 8;
var val = o.testNumber;

读取对象属性的时候如果对象有这个属性就会返回它的值。很简单,不过有意思的地方在于它的内部机制 :) 首先我们先来了解一下原型链(prototype chain)的概念,所有的对象都会有一个原型(prototype),而它们的原型也是一个对象,这就是说它们的原型也可能有自己的原型,于是原型链就形成了。在JS中,Object 的默认原型是 null ,所以:


var o = new Object();

会创建一个原型为 Object.prototype 的对象 o,由于 Object.prototype 的prototype 为空 ,所以对象 o 的原型链就只有一个,就是最原始的 Object.prototype 。但是下面的代码就复杂一点:

function MyObject1(formalParameter){ 
 this.testNumber = formalParameter; 

 
function MyObject2(formalParameter){ 
 this.testString = formalParameter; 

MyObject2.prototype = new MyObject1( 8 );
var objectRef = new MyObject2( "String_Value" );

objectRef 所指向的 MyObject2 的实例有一个原型链,原型链中的第一个对象是 MyObject1 的prototype,而 MyObject1 的 prototype 的 prototype 是最原始的 Object.prototype ,而Object.prototype的prototype为空,所以原型链至此结束。

OK。下面我们来继续说对象属性的读取,其实读取一个对象属性的过程可能会涉及到该对象原型链中的所有对象。在上面那段代码中,我们来读取下面的属性:


var val = objectRef.testString;

由于objectRef 所指向的 MyObject2 的实例上有这个名为 testString 的属性,所以就会直接把这个属性的值”String_Value”赋给变量 val 。但是:


var val = objectRef.testNumber;

我们会发现 val 会被赋值为 8 ,可是objectRef 所指向的 MyObject2 的实例上没有这个名为 testNumber 的属性啊?为什么val 并不会被赋值为 undefined 呢?因为在对象自身上找不到该属性的时候,它就会检查对象的原型链,于是发现objectRef 指向的 MyObject2 的实例的prototype 是 MyObject1 的一个实例,而在这个实例中由一个值为 8 的 testNumber 属性,那么JS就会把这个值赋给 val 。我们看到,在 MyObject1 和 MyObject2 中都没有定义一个叫做 toString 的属性,但是当我们这样获取 objectRef 的 toString :


var val = objectRef.toString;

还是可以获取到。相信聪明的你已经想到了,因为 objectRef 的原型链的末端是 Object.prototype ,而在这个对象上面由一个名为 toString 的方法。最后:


var val = objectRef.madeUpProperty;

这次 val 终于是 undefined 了,因为检查完所有原型链都找不到名为 madeUpProperty 的属性,于是只好放弃。

综上,我们可以看到,在读取对象属性的时候,会先检查对象本身,然后依次检查它的原型链中的对象,在检查过程中发现符合要求的值就终止检查,然后返回。也就是说,它会返回第一个符合要求的值。了解了对象的赋值和读取过程之后,我们会发现一个有意思的事情,如果我们在上面代码的基础上执行:


objectRef.testNumber = 3;

由于objectRef 所指向的 MyObject2 的实例上没有 testNumber 这个属性,所以就会在该实例上创建一个名为 testNumber 的属性并赋值为 3 ,注意,这里并没有改变原型链上 MyObject1 的实例上的 testNumber 属性的值。而当我们再次获取 objectRef.testNumber 的值的时候,JS 会首先检查 objectRef 所指向的实例,然后就发现有这个属性,于是直接返回它的值:3 。这样一来,objectRef 原型链上的那个值为 8 的testNumber 属性就被隐藏了起来。

阅读下一篇:Javascript Closures (2)

0
投稿

猜你喜欢

  • 和以往的总监会议一样,在某个新功能的总监级别讨论会上,很多人再次又说出了同样的看法:“我们网站的界面设计太烂了,不好看、不好用、而且很乱”。
  • 突然想到写这个话题,是基于最近在设计产品界面时,年糕一直在给我们灌输设计的品牌概念以及文化内涵要求而产生的,因之前在界面设计中也遇到一些困惑
  • 【译者的话】 作为一家非盈利性的防止青少年 * 的机构, Five Alive 希望拥有一个独特的标志来配合机构的宣传。他们决定在网站上通过竞
  • 网页编程中,在与数据库打交道的时候我们经常会碰到乱码的经常。本文就将介绍一种ASP读取MySQL数据库出现乱码的解决办法。情景再现:使用My
  • 上次谈到客户端和服务端的编码“陷阱”,其中对url编码只是提及带过,并没有做深入讨论,事实上由于浏览器环境的复杂和不一致性,我们也很容易掉进
  • 对于许多想学习JavaScript的朋友来说,无疑如何选择入门的书籍是他们最头疼的问题,或许也是他们一直畏惧,甚至放弃学习JavaScrip
  •  <script language="vbscript" runat="s
  • 又从 James Padolsey 这里得到个好的点子。在实际写脚本过程中可能有段 Javascript 和 HTML 非常相关(比如实例化
  • 什么是F型浏览?2006年4月,美国长期研究网站可用性的著名网站设计师杰柯柏·尼尔森(Jakob Nielsen)发表了一项《眼球轨迹的研究
  • 当我们使用访问一个没有声明的变量时,JS会报错;而当我们给一个没有声明的变量赋值时,JS不会报错,相反它会认为我们是要隐式申明一个全局变量。
  • Microsoft建立了一种既灵活又强大的安全管理机制,它能够对用户访问SQL Server服务器系统和数据库的安全进行全面地管理。按照本文
  • 最近遇到SQL Server 2005 输入框不能输入中文,在网上查了N久,试验了十几次奏这个法子有用:“把你表中的自动编号列放到最后面”。
  • 这是 COMSHARP CMS 团队翻译的2009年海外Web设计风潮的第二部分,着重讲解了反 Box 式布局,单页布局,多栏布局,巨型插图
  • 代码如下:DECLARE @c INT DECLARE @c2 INT SELECT @c = COUNT(1) FROM dbo.Spli
  • 目录:分析和设计组件编码实现和算法用 Ant 构建组件测试 JavaScript 组件话说上期我们讨论了队列管理组件的设计,并且给它取了个响
  • 内容摘要:本文介绍了通过获取访问者的IP地址来统计在线人数的方法,本文只是给出了实现统计在线人数的方法思路,具体代码的实现过程还得自己动手(
  • 论证完使用target=_blank并非绝对错误之后,分场景探讨如何减少新开窗口。自有意识注意这个问题,是看到蓝色经典Plod大叔在04年提
  • 人们对于那些抄袭模仿的网站有诸多抱怨,但在这篇文章中,却没有冷嘲热讽的意思。但正如他们所说,“模仿是最为忠诚的奉承形式”。“如果你确实需要借
  • 内容摘要:一般情况下,如果我们想了解股市行情,必须登录专业股票网站,输入公司代码才能看到具体股价。其实,利用XMLHTTP协议,我们每个人都
  • 关于oracle 优化的内容很多,概念庞杂,不过可以总结出一个大纲性的东西作为需要考虑的方向,然后再逐步细化。oracle优化按重要性需要考
手机版 网络编程 asp之家 www.aspxhome.com