dinghao

记录成长点滴

 

ajax-javascript-范围链、call对象与闭包

闭包基础

都知道,局部变量隐藏全局变量,为什么会隐藏?

因为函数对象的[[scope]]内部属性,闭包能实现也因为有这个对象。

Excution Context&Scope&Call Object

当函数被调用时,解释器为其创建一个上下文,当函数返回时,解释器回到最初的上下文。解释器形成一个上下文栈。上下文包含:全局上下文和局部上下文。

创建上下文会伴随一系列对象的创建,包含:

Call Object此对象包含一个arguments属性指向argumets对象。

argumentsObject:保含的是调用者指定的参数和被调用函数无关。赋值给Call Objectarguments属性。

Scope Object:创建scope对象,并加入scope链,把call Object加入到链头,然后赋值给function object的[[scope]]属性。

Variable Object在此初始化了三种类型的变量:局部变量被初始化为undefined。如果正式的参数(注意不是arguments中的参数)在arguments中有值,用值初始化,否则也初始化为undefined。初始化内部函数。Variable Object指向Call,他们相同。

上面是局部上下文,全局上下文比较简单,只包含一个globle对象。别的对象不会被创建,因为没有意义。

可以看到只要通过函数对象的[[scope]]内部属性,就能得到函数所需的所有运行信息。

注:

正式参数:这里指实际参数。

上面只是简要说明,只是解释了和闭包有关部分,并不严格,详细的参见ecma-262

Eval&with

eval创建新的上下文

with会打破现在的上下文

闭包

在Js中函数嵌套被返回时闭包就形成。因为函数有内置的[[scope]]属性,保持了内层函数的引用,也就保持了整条从内部到globle链的引用。整条链资源不能被释放,当然也能访问链上的变量。

解释闭包的例子

 

var x= 5;     //范围globle开始

 

var y=30;

function f(y){               //范围f开始

 

       

    
return function g()     //范围g开始

    
{   

              
var z=10;

        document.write(x
+y+z)

    }
                                          //范围g结束

}
                                 //范围f结束

 

var f1 = f(5);  输出20    //范围globle结束

在g()被执行时,g()的[[scope]]会指向下面的链:

首先是g的call object:包含变量z。

然后是g的scope对象

再后面是f的call objec:包含y

再后是f的scop

再后是globle object:包含x,y

 

因此执行时,由于g存活,整条链就可以使用,闭包得以形成。变量定位也从当前call object开始,会隐藏同名的y(参数y隐藏全局y)。

另一种隐藏是prototype chain,虽然都隐藏变量,但他们完全不同,也没有任何关系,详细见,上一篇继承

MicrosoftAjax.js中的闭包

createCallback& createDelegate

事件不用闭包的实现方式:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >

<head>

    
<title>Untitled Page</title>

</head>

<body>

<input type="button" id="Submit1" value="Test Closure" />

 

<script type="text/javascript">

    
function TestC(buttonId, message)

    
{

        
this._message = message;

        
var btn = document.getElementById(buttonId);

        btn.onclick 
= function(){m.showMessage()}

    }


    

    TestC.prototype.showMessage 
= function()

    
{

        alert(
this._message);

    }


 

    
var m = new TestC('Submit1', 'aaaa');

 

</script>

 

</body>

</html>

下面的语句定死了函数:

 btn.onclick = function(){m.showMessage()}

但是如果用btn.onclick=this.showMessage;由于this指向button,代码又没有办法工作。

 

只能借助闭包和Apply:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >

<head>

    
<title>Untitled Page</title>

</head>

<body>

<input type="button" id="Submit1" value="Test Closure" />

 

<script type="text/javascript">

 

   
var createDelegate= function Function$createDelegate(instance, method) {

    
/// <param name="instance" mayBeNull="true"></param>

    
/// <param name="method" type="Function"></param>

    
/// <returns type="Function"></returns>      

     
return function() {

        
return method.apply(instance, arguments);

    }


}


    
function TestC(buttonId, message)

    
{

        
this._message = message;

        
var btn = document.getElementById(buttonId);

     

     btn.onclick
=this.showMessage;

 

    }


    

    TestC.prototype.showMessage 
= function()

    
{

        alert(
this._message);

    }


 

    
var m = new TestC('Submit1', 'aaaa');

 

</script>

 

</body>

</html>

 

更多闭包例子

下面文中有很多闭包例子,可以在页面执行,看到效果,可以直观感受下什么是闭包

http://www.javascriptkit.com/javatutors/closures.shtml

看看最新的JS调试器:

http://weblogs.asp.net/scottgu/archive/2007/07/19/vs-2008-javascript-debugging.aspx
总的介绍
http://www.cnblogs.com/bluewater/archive/2007/07/17/821471.html
namespace
http://www.cnblogs.com/bluewater/archive/2007/07/18/822485.html
继承
http://www.cnblogs.com/bluewater/archive/2007/07/19/823815.html

0
0
(请您对文章做出评价)
« 上一篇:Ajax-Javascript-继承
» 下一篇:为啥不用ActiveRecord

posted on 2007-07-20 17:39 思无邪 阅读(2543) 评论(8)  编辑 收藏

评论

#1楼 2007-07-20 17:46 木野狐      

不错,如果调整一下字体和排版格式会更好。   回复  引用  查看    

#2楼 2007-07-21 07:22 菌哥      

看起来吃力!   回复  引用  查看    

#3楼 2007-07-21 08:43 蛙蛙池塘      

还真看不懂,呵呵   回复  引用  查看    

#4楼 2007-07-21 12:54 zzskypig

确实,感觉很晕   回复  引用    

#5楼[楼主] 2007-07-21 20:48 思无邪      

@菌哥
@蛙蛙池塘
@zzskypig
不会吧,我觉得已经很通俗了,先看看黑体的例子。
下面是这系列的术语说明:
Function,Object都是指Js中内置的函数,Object不同于OO中的对象。
objects指名称对的集合,类似于OO中的对象,文中的对象一般指objects
Function object,指Function中起Object作用的部分,一般翻译为函数对象。
MA指MicrosoftAjax.js文件,不是指MicrosoftAjax

  回复  引用  查看    

#6楼[楼主] 2007-07-21 21:46 思无邪      

闭包涉及到JS的运作机制,本身就难理解。我也是看了一周的资料才弄明白。一下看不懂也算正常,呵呵
这篇也没有从最基本的说起,大部分都在解释闭包中最难理解的部分,也就是黑体部分。
基本的东西:
其实对C#了解的人首先要明白:
Function也是Object。千万不要说成函数也是对象,看到高级程序设计这样说,绝对是误导。Object和对象完全没有关系,ecma的objects才可以类似的说成对象。
如果能看懂,MA中Function和Type的关系,自定义Function和系统的如Error是怎么得到Type和Function功能的,就可以说理解了这句。
这是最基本的。




  回复  引用  查看    

#7楼[楼主] 2007-07-21 21:51 思无邪      

接下来就是范围链和Call 对象,他们涉及到js运行机制。
再次是Prototype chain。
我觉得,理解了这三个,就可以整体把握JS,就能体会Js如何能够模拟OO。
如果还看晕,只能去搜索google了。也可以看看我前几篇再看这个。刚加了链接。
  回复  引用  查看    

#8楼 2009-01-04 16:20 游客1001[未注册用户]

能不能用下面这种方式呢?
<input type="button" id="Submit1" value="Test Closure1" />
<input type="button" id="Submit2" value="Test Closure2" />
<script type="text/javascript">

function TestC(buttonId, message)

{

var _this = this;
this._message = message;

var btn = document.getElementById(buttonId);

btn.onclick = function(){_this.showMessage()}

}



TestC.prototype.showMessage = function()

{

alert(this._message);

}

var m = new TestC('Submit1','Submit1');
var n = new TestC('Submit2','Submit2');
</script>
  回复  引用    

导航

统计

搜索

 
 

常用链接

我参与的团队

随笔分类

随笔档案

收藏站点

文章收藏

积分与排名

最新评论

阅读排行榜