论坛首页 Web前端技术论坛

EXTJS源码分析与开发实例宝典-superclass()不当应用

浏览 4848 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (1)
作者 正文
   发表时间:2010-01-19   最后修改:2010-01-20

看了第三章前半部分extend作者实现的superclass() 部分,不知道为何在分析extjs源码中途要创造这样一个继承机制,看起来像 crockford 的uber 方法,但是觉得有点问题啊,先记下来


作者实现:

 

extend : function() {
					// inline overrides
					var io = function(o) {
						for (var m in o) {
							this[m] = o[m];
						}
					};
					var oc = Object.prototype.constructor;
					var superclass = function(sp) {

						var s = function() {
							var name = (s.caller || {}).name;
							var len = arguments.length, t = this;
							var supper = arguments.callee.superclass;
							if (!name)
								for (var n in t) {
									if (t[n] == s.caller) {
										name = n;
										break;
									}
								}

							if (len > 0 && name) {
								//alert(name);
								var callArgs = Array.prototype.slice.call(
										arguments, 0);
								Array.prototype.splice.apply(callArgs, [0, 1]);
								return supper[name](callArgs);
							}
							return supper;
						}
						s.superclass = sp;
						return s;
					};

					return function(sb, sp, overrides) {
						if (typeof sp == 'object') {
							overrides = sp;
							sp = sb;
							sb = overrides.constructor != oc
									? overrides.constructor
									: function() {
										sp.apply(this, arguments);
									};
						}
						var F = function() {
						}, sbp, spp = sp.prototype;
						F.prototype = spp;
						sbp = sb.prototype = new F();
						sbp.constructor = sb;
						sb.superclass = spp;
						if (spp.constructor == oc) {
							spp.constructor = sp;
						}
						sb.override = function(o) {
							Ext.override(sb, o);
						};
						sbp.override = io;
						Ext.override(sb, overrides);
						sb.extend = function(o) {
							Ext.extend(sb, o);
						};
						sbp.superclass = superclass(spp);
						return sb;
					};
				}(),

 

this.superclass() 实际上直接就访问到了父类构造函数的原型对象,那么以此为原理可以直接调用父类的方法,作者也说了这样的话对象实例(this)就丢掉了,到这还好。

 

例子: (下载)

 

不过我不大清楚这样子脱离了实例this的上下文调用还有什么用,就开始看例子,例子就很随意了:(稍微改了一下)

 

var Animal = function(q) {
  //alert("this is Animal constructor");
	this.name = q[0][0].tag;
	this.age = q[0][0].age;
};
Animal.prototype.getAge = function() {
	 alert(this.name+"'age is "+this.age);
};
Animal.prototype.getName = function() {
	// alert("this is the animal Name!");
};
var Cat = Ext.extend(Animal, {
	name : 'cat',
	age : 5,
	yy : 'aa',
	constructor : function() {
		//alert("this is Cat constructor");
		this.superclass().constructor(arguments);
	},
	getAge : function() {
		//alert(this.name + "'age is " + this.age);
		this.superclass().getAge();
		this.name = 'modefy';
		this.xx = 'aa';
		//alert(this.yy);
	}
});

var homeCat = function() {
	//alert("this is homeCat constructor");
	this.superclass().constructor(arguments);
};

Ext.extend(homeCat, Cat, {
	name : 'homeCat',
	age : 3,
	homeCat : true,
	getAge : function() {
		// alert(this.name+"'age is "+this.age);
		this.yy = 'yy';
		this.superclass(this);// .getAge();
		// alert(this.name);
		// alert(this.xx);
	}
});
var myCat = new homeCat({age:99,tag:"first"});
myCat.getAge();
//console.dir(Animal.prototype);
var myCat2 = new homeCat({age:-99,tag:"second"});
myCat2.getAge();
myCat.getAge();

调用代码:

 

var myCat = new homeCat({age:99,tag:"first"});
myCat.getAge();
//console.dir(Animal.prototype);
var myCat2 = new homeCat({age:-99,tag:"second"});
myCat2.getAge();
myCat.getAge();


输出为:

 

first'age : 99

second'age -99

second'age -99


可见前面对象的父类数据已经被覆盖掉了.没有达到模拟传统面向对象语言继承的机制

 

分析:

1.this.superclass().constructor(arguments) ,这应该是完全不合道理的 ,要么用call,要么apply,直接传个arguments似乎不妥。


2.有上述可知:

this.superclass()为父类构造函数的原型,那么在原型调用函数 this.super().xx();那么在xx中的this就变成了当前函数原型对象,那么我如果修改了this的某个数据属性话,该原型所关联的所有对象实际上都发生了变化,并且完全改变了下面代码的语义:

 

var Animal = function(q) {
  alert("this is Animal constructor");
	this.name = 'animal';
	this.age = q;
};


用this修改的是函数的原型对象,而不是实例对象本身了!


比如上述我传了个

 

var myCat = new homeCat(99);
myCat.getAge();


那么执行后在firebug中查看

 

console.dir(Animal.prototype);

 


可见并应该与实例关联的数据却被关联到了公有的父类原型对象上面,作者想模拟传统面向对象的实例对象的父类数据部分是失败的,js中父类原型对象是公用的, 那么这样还有什么意义,生成多个对象的话,其父类的数据并不能保存下来,都被后来对象冲掉了。

 

3.总之:我觉得原型对象还是只用来保存函数以及一些所有实例对象都不变的数据比较好,其他对象关联数据就不要保存在里面了。

 

ps:书中出现这样一段:

 

this.superclass().getXY.apply(this,arguments)

 

更令我疑惑了,apply后获得了实例的this上下文,那么在父类 getXY 中再调用

 

this.superclass().getXY.apply(this,arguments)


岂不会造成死循环? this.superclass永远都是同一个new出来的实例对象的superclass而不会调用原型链往上的对应superclass


 

 

 

 

 

  • 大小: 9.7 KB
   发表时间:2010-01-20  
如果需要当前实例的上下文,采用这种方式:
this.superclass().getXX.apply(this,arguments)

extjs的继承也是需要采用apply或call来改变上下文作用域,如
Morik.Office.LeftMenu.superclass.initEvents.call(this);

可见其简化一些。


当然如果 采用this.superclass().getXX.apply(this,arguments)。

那么其父类中的getXX的作用域就是当前实例。getXX函数中一般不能采用
this.superclass().getXX.apply(this,arguments),这时得到的是当前实例的父亲类的getXX,而不是其祖父类中的getXX。所以在当前实例的父类不能改变上下文作用域。


说明了这种this继承方式的缺陷,也说明了如mootools中的this.supper有着同样的缺陷。


所以我在书中说明了,如果是最终类(没有子类),则可以采用了这种this.superclass().getXX.apply(this,arguments)方式,对于非最终类,采用extjs的继承方式。

而我们写的大量的类一般都是最终类。



另外书中的例子并不是很随意采用的,它采用了mootools讲解继承关系的实例。

有什么问题,请继续探讨。
0 请登录后投票
   发表时间:2010-01-20  
1.this.superclass().constructor(arguments) ,这应该是完全不合道理的 ,要么用call,要么apply,直接传个arguments似乎不妥。

从形式上来看,这样不妥。但是从面对对象类的构造函数的角度来看,倒不是完全不能接受。这样无论如何都减化了extjs的继承方式。

0 请登录后投票
   发表时间:2010-01-20  
不过采用constructor(arguments) 直接伟入参数的确有问题,它不能改变作用域,其数据不能保存在当前实例中,应该通过apply或call来进行改变作用域,把当前实例的父类的数据保存在当前实例之中,
这样就能达到我自己想要实现的目标。

要说明的是这种继承只是一种扩展,另一种选择。有一些情况还是适用的,在Js中的确做不到完全面向对象中的那样继承。
0 请登录后投票
   发表时间:2010-01-20  
书中肯定还会有很多问题,希望能更多地指出,便于改进,也便于提高。
0 请登录后投票
论坛首页 Web前端技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics