- 浏览: 5523 次
- 性别:
- 来自: 北京
最近访客 更多访客>>
文章分类
最新评论
-
yyliuliang:
ls朋友谈下企业库如何蹩脚啊
自己动手写个orm实现(1) -
yza0088:
.Net领域的ORM已经很完善了。例如ActiveRecord ...
自己动手写个orm实现(1)
原文: 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来提升Web应用的性能和交互性。 一、ASP.NET AJAX的核心组件 1. UpdatePanel:这是ASP.NET AJAX中最常见的控件,它允许在后台异步处理服务器端事件,而无需完整页面生命...
10. 客户端编程特性:深入探讨ASP.NET AJAX客户端库的特性,包括对象交互、JSON序列化和反序列化、客户端事件处理等。 11. 访问Session、Cache和Application对象:在Ajax操作中,可以方便地访问和操作服务器端的...
【ASP.NET AJAX深入浅出系列课程(30):ASP.NET AJAX的相关扩展(下)】 在本课程中,我们将深入探讨ASP.NET AJAX的扩展性,这是Microsoft为Web开发人员提供的一种强大工具,允许他们创建更动态、响应更快的网页应用。...
在本课程“ASP.NET AJAX深入浅出系列课程(29):ASP.NET AJAX的相关扩展(上)”中,我们将探讨如何利用ASP.NET AJAX的扩展功能来提升Web应用的用户体验。 首先,ASP.NET AJAX的核心组件包括客户端脚本库和服务器端...
### ASP.NET AJAX深入浅出系列课程之客户端访问WebService(下) #### 重要知识点解析 **一、改变客户端访问时的方法名** 在客户端访问WebService时,由于JavaScript语言的限制,无法直接支持方法重载(overload...
ASP.NET AJAX Control Toolkit是微软为ASP.NET开发者提供的一套强大的客户端脚本库,它扩展了ASP.NET AJAX的功能,使得Web应用程序能够实现更丰富的用户交互和更高效的页面更新。这个工具包是针对.NET Framework 3.5...
首先,我们要理解ASP.NET AJAX的核心是Microsoft的AJAX库,它扩展了ASP.NET,引入了部分更新(Partial Page Rendering)和异步通信的能力,通过XMLHttpRequest对象实现了后台与前端的无刷新交互。这使得开发者可以在...
ASP.NET AJAX 控件是微软为开发富客户端Web应用程序提供的一种技术,它允许开发者在不刷新整个页面的情况下更新页面部分,从而提升用户体验。AJAX(Asynchronous JavaScript and XML)的核心是利用JavaScript实现...
ASP.NET AJAX(Asynchronous JavaScript and XML)是一种技术框架,它扩展了Microsoft的ASP.NET平台,引入了异步处理能力,使Web应用程序能够实现更流畅、更快速的用户体验,无需整个页面刷新。在ASP.NET AJAX中,...
ASP.NET AJAX(Asynchronous JavaScript and XML)是一种微软提供的技术,用于构建富客户端应用程序,它可以实现页面的局部更新,即无刷新效果。在这个“史上最简单AJAX实现无刷新评论例子”中,我们将探讨如何利用...
ASP.NET AJAX(Asynchronous JavaScript and XML)控件是微软.NET框架的一部分,用于构建富客户端Web应用程序,它提供了更流畅、响应更快的用户体验。在ASP.NET中,AJAX控件允许部分页面更新,而不是整个页面刷新,...
**ASP.NET AJAX系列7:深入理解自定义异常处理** 在ASP.NET AJAX开发中,异常处理是不可或缺的一部分。本文将深入探讨如何在ASP.NET AJAX应用程序中有效地处理自定义异常,以提高应用的稳定性和用户体验。 首先,...
在“ASP.NET AJAX客户端访问Web Service及面向对象类型系统实例”中,我们将深入探讨如何利用AJAX技术在客户端与Web服务进行交互,以及如何在ASP.NET中应用面向对象的编程概念。 首先,我们要理解ASP.NET AJAX的...
在这个"ASP.NET AJAX深入浅出系列课程(24):UpdatePanel与服务器端脚本控件(上)"中,我们将探讨两个关键概念:UpdatePanel和服务器端脚本控件,这两个元素对于理解ASP.NET AJAX的工作原理至关重要。 首先,我们来...
在这个“ASP.NET AJAX深入浅出系列课程(10)”中,我们将聚焦于如何基于Microsoft AJAX Library来扩展客户端组件,以实现更加灵活和定制化的功能。 1. Microsoft AJAX Library基础 - AJAX库的核心是MicrosoftAjax....
**ASP.NET AJAX深入浅出系列课程(8)** 在这一系列课程中,我们将深入探讨JavaScript中的原生对象以及Microsoft AJAX Library中的相关扩展。这是一门针对ASP.NET开发者的高级课程,旨在帮助他们更好地理解如何利用...
ASP.NET AJAX 深入浅出系列课程是一个全面讲解如何使用 ASP.NET 平台与 AJAX 技术结合进行高效Web开发的教程。本系列课程旨在帮助开发者深入理解 Microsoft AJAX Library 的核心概念,以及如何利用其面向对象的特性...
【ASP.NET AJAX控件应用配置】是针对ASP.NET框架中使用AJAX技术进行网页交互优化的一种实践。在ASP.NET中,AJAX(Asynchronous JavaScript and XML)允许开发人员创建具有部分页面更新功能的动态、响应迅速的Web应用...