`
yyliuliang
  • 浏览: 5404 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
社区版块
存档分类
最新评论

深入ASP.NET AJAX : 对象继承体系

 
阅读更多

原文: ASP.NET AJAX In-Depth: Object Inheritance 作者:Stephen Walther

来源:http://www.cnblogs.com/dflying/archive/2008/03/16/1108763.html

---------------------------------------------------------------------

本文的目的很简单 : 就是在享用ASP.NET AJAX框架对象继承体系带来的好处同时,我想弄清在这鼓里究竟埋了什么东东。 让我们从这段简单的代码开始 。。。

// 代码1 – AjaxInheritance.aspx
1: <script type="text/javascript">
2:
3: function BaseControl()
4: {
5: this._propA = "BaseControl propA";
6: this._propB = "BaseControl propB";
7: }
8:
9: BaseControl.prototype =
10: {
11: get_propA : function() {return this._propA;},
12: set_propA : function(value) {this._propA = value; },
13:
14: get_propB : function() {return this._propB; },
15: set_propB : function(value) {this._propB = value; }
16: }
17:
18: BaseControl.registerClass("BaseControl");
19:
20:
21: function TreeViewControl()
22: {
23: TreeViewControl.initializeBase(this);
24: this._propA = "TreeViewControl propA";
25: }
26:
27: TreeViewControl.prototype =
28: {
29: get_propA : function() {return this._propA;},
30: set_propA : function(value) {this._propA = value; }
31: }
32:
33: TreeViewControl.registerClass("TreeViewControl", BaseControl);
34:
35: var treeView1 = new TreeViewControl();
36:
37: alert( treeView1.get_propA() ); // displays "TreeViewControl propA"
38: alert( treeView1.get_propB() ); // displays "BaseControl propB"
39:
40:
41: </script>



上面的这段代码定义了BaseControl和TreeViewControl两个对象。他们兴许代表了web页里展示的两个对象。TreeViewControl继承自BaseControl。

首先,BaseControl定义了一个名为BaseControl的构造函数。构造函数初始化了名为_propA和_propB的两个变量。接下来,用以提供向外界提供访问私有变量_propA,_propB的途径,set,get方法被作为公开属性添加到BaseControl的原型中。最后,利用ASP.NET AJAX客户端框架提供的registerClass方法,将BaseControl对象注册为一个类。在稍后我们将讨论调用registerClass方法其中的细节。

其后,定义一个新对象TreeViewControl。大家注意到,TreeViewControl的构造函数里调用了一个名为initializeBase的ASP.NET AJAX方法。后文同样会就这个方法进行讨论。

类似BaseControl,TreeViewControl通过调用registerClass注册为一个类,但是TreeViewControl确是作为BaseControl的子类.传递到registerClass方法中的第二个参数能够让你指定父类

最后,创建了名为treeView1的TreeViewControl实例,get_propA() 和get_propB() 方法被调用并显示出测试结果

理解registerClass()方法

为了探究上文中的细节,我们第一个要了解的ASP.NET AJAX方法就是registerClass.它接收以下三个参数

· typeName – 注册的类名

· baseType – 被注册类的父类 [ 可选 ]

· interfaceTypes – 被注册类需要实现的接口列表 [ 可选 ]

通过参阅Microsoft Ajax框架中的MicrosoftAjax.debug.js文件你能够将registerClass其中细节一览无余.

下面截取的代码片段向我们展示了registerClass方法的相关信息

// 代码2 – MicrosoftAjax.debug.js registerClass() method
1: Type.prototype.registerClass = function(typeName, baseType, interfaceTypes) {
2:
3: var parsedName;
4: try {
5: parsedName = eval(typeName);
6: }
7: catch(e) {
8: throw Error.argument('typeName', Sys.Res.argumentTypeName);
9: }
10: if (parsedName !== this) throw Error.argument('typeName', Sys.Res.badTypeName);
11: if (Sys.__registeredTypes[typeName]) throw Error.invalidOperation(String.format(Sys.Res.typeRegisteredTwice, typeName));
12: if (baseType && !baseType.__class) throw Error.argument('baseType', Sys.Res.baseNotAClass);
13: this.prototype.constructor = this;
14: this.__typeName = typeName;
15: this.__class = true;
16: if (baseType) {
17: this.__baseType = baseType;
18: this.__basePrototypePending = true;
19: }
20: Sys.__upperCaseTypes[typeName.toUpperCase()] = this;
21:
22: Sys.__registeredTypes[typeName] = true;
23: return this;
24: }


在上面的代码中你首先需要注意的就是registerClass是一个名为"Type"对象的方法(它定义在Type原型中).那Type是一个什么东东呢?原来它只是JavaScript中Function的别名而已. Microsoft AJAX框架用以这段代码创建别名:

window.Type = Function;

这样一来,我们就能够在任何function中调用registerClass方法了,通常来说,你应该在构造函数中调用它.

从下面的代码开始,让我们步步深入,探究registerClass的其中种种.

1: var parsedName;
2: try {
3: parsedName = eval(typeName);
4: }
5: catch(e) {
6: throw Error.argument('typeName', Sys.Res.argumentTypeName);
7: }
8: if (parsedName !== this) throw Error.argument('typeName', Sys.Res.badTypeNam

当你调用registerClass方法时,第一个字符串型参数应该是当前调用者的对象名. 用以下你能够调用registerClass方法注册名为TreeViewControl的类:

TreeViewControl.registerClass(“TreeViewControl”);

这样捣鼓看起来是不是显得有些多余?为什么需要引用TreeViewControl两次呢:一次是作为对象,一次是字符串形式. 我认为这样做的目的是为了获取字符串形式的函数名,用以校验赋予的string值是否等价于真实的参数. 有一种方法,我们可以避免类似的冗余:将要注册的函数内调用toString()方法来检验函数名 :

this.toString().match(/( \w+)/)[0]

我推测,Microsft AJAX没有这样做的原因可能是出于性能考虑.

接下来的代码

1: if (Sys.__registeredTypes[typeName]) throw Error.invalidOperation(String.format(Sys.Res.typeRegisteredTwice, typeName));
2: if (baseType && !baseType.__class) throw Error.argument('baseType', Sys.Res.baseN


第一行代码能够防止同一类名被多次注册,第二行则验证传入的父类参数是否实际存在.

this.prototype.constructor = this;

这行代码很好很有趣.它fix了Javascript中constuctor属性的bug,如下

// 代码3 – BadConstructor.js
1: <script type="text/javascript">
2:
3: // Bad Constructor
4: function A() {}
5: function B() {}
6:
7: B.prototype = new A();
8:
9: var x = new B();
10: alert( x.constructor ); // Returns A
11:
12:
13: // Good Constructor
14: function A() {}
15: function B() {}
16:
17: B.prototype = new A();
18: B.prototype.constructor = B; // fix constructor
19:
20: var x = new B();
21: alert( x.constructor ); // Returns B
22:
23:
24: </script>



如上,构造函数应该返回当前构造对象的函数名.不幸的是,因为prototype chain的存在,constructor属性返回了错误的构造函数,它返回的是构造prototype chain顶部对象的函数名称.当[代码3]中的x.constructor第一次被调用,其返回了一个错误值.经过后面的处理,x.constructor才返回了正确值.

1: this.__typeName = typeName;
2: this.__class = true;
3: if (baseType) {
4: this.__baseType = baseType;
5: this.__basePrototypePending = true;
6: }
7: Sys.__upperCaseTypes[typeName.toUpperCase()] = this;
8:
9: Sys.__registeredTypes[typeName] = true;


在这里,为当前构造函数添加了一些属性:__typeName, __class,__baseType, 和 __basePrototypePending.这些属性会被一些方法例如initializeBase()进行反射处理,详情稍后讨论.

最后,构造函数名被Sys命名空间中的__upperCaseTypes 和__registeredTypes数组所保存.__upperCaseTypes被Type.parse方法用递对象名来生成对象实例.__registeredTypes数组则被registerClass方法用来确认类没有被重复注册.你需要注意到的是registerClass方法并没有修改prototype属性,直到initializeBase的出现....

理解 initializeBase 方法

你可以在派生类的构造函数中调用initializeBase方法.例如在[代码1]中,我们在TreeViewControl的构造函数中调用initializeBase方法.如果你不这么做,派生类将不能从其父类中继承到任何东东.

1: Type.prototype.initializeBase = function(instance, baseArguments) {
2: if (!this.isInstanceOfType(instance)) throw Error.argumentType('instance', Object.getType(instance), this);
3: this.resolveInheritance();
4: if (this.__baseType) {
5: if (!baseArguments) {
6: this.__baseType.apply(instance);
7: }
8: else {
9: this.__baseType.apply(instance, baseArguments);
10: }
11: }
12: return instance;
13: }

和registerClass方法一样,initializeBase也被创建为Function对象的方法(Function对象在Microsoft Ajax中的别名为Type). 这样你就能在任何function中调用initializeBase.这样做的意义在于你能够在当前function或当前function的父类的构造函数中调用initializeBase

if (!this.isInstanceOfType(instance))

throw Error.argumentType('instance', Object.getType)

这段代码验证了传递到initializeBase方法中的实例参数是否和当前调用者(或是当前调用者的父类)相同.如下

// 代码5 – BadInitializeBase.js
1: <script type="text/javascript">
2:
3: function A() {}
4: A.registerClass("A");
5: function B() {}
6: B.registerClass("B");
7: function C()
8: {
9: A.initializeBase(this); // throws exception
10: B.initializeBase(this); // ok
11: C.initializeBase(this); // ok
12: }
13: C.registerClass("C", B);
14:
15: var x = new C();
16:
17:
18: </script>



注意,下面这段非常重要!

this.resolveInheritance();

通过调用resolveInheritance方法修改了当前对象的原型

// 代码 6 – MicrosoftAjax.debug.js resolveInheritance()
1: Type.prototype.resolveInheritance = function() {
2: if (this.__basePrototypePending) {
3: var baseType = this.__baseType;
4: baseType.resolveInheritance();
5: for (var memberName in baseType.prototype) {
6: var memberValue = baseType.prototype[memberName];
7: if (!this.prototype[memberName]) {
8: this.prototype[memberName] = memberValue;
9: }
10: }
11: delete this.__basePrototypePending;
12: }
13: }


resolveInheritance方法检验构造函数的__basePrototypePending属性是否为真.当你注册一个新的类时,registerClass方法会将__basePrototypePending设置为true.
接下来,resolveInheritance方法会被继承链中每个对象的构造函数重复调用.自顶向下,继承链中每个对象的属性被依次拷贝.

// 代码 7 – AjaxInheritance.js

1: <script type="text/javascript">
2:
3: function BaseControl()
4: {
5: this._propA = "BaseControl propA";
6: this._propB = "BaseControl propB";
7: }
8:
9: BaseControl.prototype =
10: {
11: get_propA : function() {return this._propA;},
12: set_propA : function(value) {this._propA = value; },
13:
14: get_propB : function() {return this._propB; },
15: set_propB : function(value) {this._propB = value; }
16: }
17:
18: BaseControl.registerClass("BaseControl");
19:
20:
21: function TreeViewControl()
22: {
23: TreeViewControl.initializeBase(this);
24: this._propA = "TreeViewControl propA";
25: }
26:
27: TreeViewControl.prototype =
28: {
29: get_propA : function() {return this._propA;},
30: set_propA : function(value) {this._propA = value; }
31: }
32:
33: TreeViewControl.registerClass("TreeViewControl", BaseControl);
34:
35: var treeView1 = new TreeViewControl();
36:
37: alert( treeView1.get_propA() ); // displays "TreeViewControl propA"
38: alert( treeView1.get_propB() ); // displays "BaseControl propB"
39:
40:
41: </script>


在TreeViewControl的构造函数中调用initializeBase方法时,resolveInheritance方法亦被调用.resolveInheritance方法检索TreeViewControl的父类对象.在这里,TreeViewControl的父类是BaseControl,BaseControl的每一个属性都被拷贝到TreeViewControl的constructor原型中.

为什么当前对象原型的属性只能从父类中拷贝呢? 换言之,why are theprototypes flattened? 出于性能原因? 如果原型链中的所有属性都拷贝到最底层中,那么就没有必要解析原型链中的全部属性.

在FireFox中,下面表达式返回true

alert( treeView1.__proto__.hasOwnProperty("get_propB") ); // displays true

__proto__ property是FireFox的专有属性,表示了当前对象的原型.hasOwnProperty方法只有当一个属性为对象的本身属性而不是从原型链中继承时才返回true.上述代码显示了该原型已被flattened并且读取该属性已脱离原型链.

initializeBase方法执行的最后一段代码如下

1: if (this.__baseType) {
2: if (!baseArguments) {
3: this.__baseType.apply(instance);
4: }
5: else {
6: this.__baseType.apply(instance, baseArguments);
7: }
8: }

这段代码检验了当前的构造函数是否通过registerClass方法指定父类.如果存在父类,apply方法将父类已创建的对象传递给当前的构造函数.apply方法展示了treeView1对象是如何获得_propA和_propB对象的.

 

分享到:
评论

相关推荐

    [ASP.NET.AJAX编程参考手册(涵盖ASP.NET.3.5及2.0)].(美)霍斯拉维.扫描版.pdf

    本书通过大量实例、深入的描述以及代码分析,全面涵盖了ASP.NET AJAX服务器端和客户端框架。书中的所有代码都通过了ASP.NET 2.0和ASP.NET 3.5的测试。通过本书,您将学习到这些框架之间是如何进行协同以满足AJAx...

    html 登录ajax请求继承.net Form验证和JS解析cookie

    一个静态登录页面,用ajax想.cs后台请求,前台解析cookie的方法。其中用到了.net form票据验证方式

    庖丁解牛:纵向切入ASP.NET 3.5控件和组件开发技术

    第1章 服务器控件概述及开发环境部署 .1 1.1 自定义服务器控件 1 1.2 服务器控件在软件开发过程中的作用 1 ...附录a .net 3.5技术教程系列——collection/asp.net ajax/ silverlight/jquery ...646

    系统学习asp.net Ajax中GridView、UpdatePanel、UpdateProgress、Timer使用 .

    1.一简单地过一下每个控件 1.最简单的示例 2.UpdatePanel 3.UpdateProcess 4.Timer 2.二客户端脚本编程 1.命名空间类成员接口继承枚举 3.三实践开发 1.用Ajax让GridView的行显示提示框

    asp.net知识库

    深入剖析ASP.NET组件设计]一书第三章关于ASP.NET运行原理讲述的补白 asp.net 运行机制初探(httpModule加载) 利用反射来查看对象中的私有变量 关于反射中创建类型实例的两种方法 ASP.Net应用程序的多进程模型 NET委托...

    ASP.NET.4揭秘

    9.3.5 使用asp.net的profileparameter对象319 9.3.6 使用querystringparameter对象320 9.3.7 使用sessionparameter对象322 9.4 通过程序执行sqldatasource命令323 9.4.1 添加ado.net参数324 9.4.2 执行insert、...

    ASP.NET 3.5开发大全 (中文 PDF 完整书签 非扫描)

    第2章:在进行ASP.NET应用程序开发前,首先需要了解ASP.NET应用程序开发的最主要的编程语言C#,由于ASP.NET应用程序是基于面向对象的思想的,所以C#编程语言也包括多种面向对象的特性,包括多态和继承等,本章讲解了...

    Asp.Net+Ajax+Jquery+Json无刷新分页

    1.无刷新分页控件,以Northwind数据库为示例, 2.支持多种分页样式选择,也可以自己修改源代码自定义 3.可以单击任意字段排序 4.MsSql数据库封装访问类,可以修改代码...5.继承自IHttpHandler接口,实现http请求代理

    VS2005 C#简介与讲义

    C#简介与讲义 很全面的讲解! C#简介与讲义 ASP.NET Ajax 面向对象 继承 封装 多态

    ASP.NET开发大全

    第2章:在进行ASP.NET应用程序开发前,首先需要了解ASP.NET应用程序开发的最主要的编程语言C#,由于ASP.NET应用程序是基于面向对象的思想的,所以C#编程语言也包括多种面向对象的特性,包括多态和继承等,本章讲解了...

    ASP.NET 3.5 开发大全

    第2章:在进行ASP.NET应用程序开发前,首先需要了解ASP.NET应用程序开发的最主要的编程语言C#,由于ASP.NET应用程序是基于面向对象的思想的,所以C#编程语言也包括多种面向对象的特性,包括多态和继承等,本章讲解了...

    ASP.NET 控件的使用

    15.1.13 在组件中使用ASP.NET内部对象 481 15.2 创建组件库 484 15.2.1 编译组件库 484 15.2.2 向类库中添加引用 486 15.3 构架思考 488 15.3.1 创建多层应用程序 489 15.3.2 创建用户界面层 489 15.3.3 创建业务...

    asp.net mvc 分页控件 包含ajax分页 最简单

    2、自己要坐分页的Model继承至 INetMvcPage 3、在页面上 @PageHtmlHelper.PartialPage(Model) 就是底部页码条 三步实现分页。 对分页样式不满意可以自己修改我的DLL源代码。DLL为VS2008编写。支持MVC2和MVC3 有什么...

    [ASP.NET Ajax] ECMAScript基础类以及Asp.net Ajax对类lt;Objectgt;的扩展

    由于我对JavaScript和薄弱,所以在看Asp.net Ajax类库的同时也翻出了ECMAScript顺便学习学习。在.NET中所有类都是继承自Object,同样在JS中也一样说有都继承Object,因此如果对Object进行了扩展,那所有继承Object类...

    ASP.NET3.5从入门到精通

    1.1.6 ASP.NET 3.5 AJAX 1.2 .NET 应用程序需框架 1.2.1 什么是.NET 应用程序框架 1.2.2 公共语言运行时(CLR) 1.2.3 .NET Framework 类库 1.3 安装Visual Studio 2008 1.3.1 安装Visual Studio 2008 1.3.2 主窗口 ...

    ASP.NET 2.0+SQL Server 2005全程指南-源代码

    第5章 ASP.NET 2.0对象、状态和配置 5.1 Response对象和Request对象 5.1.1 Response对象 5.1.2 Request对象 5.2 HTTP请求上下文 5.2.1 应用程序状态 5.2.2 Server对象 5.2.3 使用Server对象中Execute()和...

    ASP.NET 3.5 开发大全 压缩包2

    第2章:在进行ASP.NET应用程序开发前,首先需要了解ASP.NET应用程序开发的最主要的编程语言C#,由于ASP.NET应用程序是基于面向对象的思想的,所以C#编程语言也包括多种面向对象的特性,包括多态和继承等,本章讲解了...

    ASP.NET 3.5 开发大全 压缩包1

    第2章:在进行ASP.NET应用程序开发前,首先需要了解ASP.NET应用程序开发的最主要的编程语言C#,由于ASP.NET应用程序是基于面向对象的思想的,所以C#编程语言也包括多种面向对象的特性,包括多态和继承等,本章讲解了...

    ASP.NET 3.5 开发大全word课件

    1.1.6 ASP.NET 3.5 AJAX 1.2 .NET应用程序需框架 1.2.1 什么是.NET应用程序框架 1.2.2 公共语言运行时(CLR) 1.2.3 .NET Framework 类库 1.3 安装Visual Studio 2008 1.3.1 安装Visual Studio 2008 1.3.2 主窗口 ...

Global site tag (gtag.js) - Google Analytics