Ajax-Javascript-继承
继承只是在用OO的术语描述Js,不能用OO继承来理解Js的继承。Js的继承根据实现方式不同,结果也不同。如Ma的继承打破了prototype chain,和常用的继承实现方式不同。这里只谈基于prototype的继承。
Prototype链
由于继承,prototype会形成链。链从当前的prototype开始,到Object结束。Prototypechain是许多Js方法的基础,如变量定位机制:先查找构造函数内的变量,即obj自身,没有会顺着prototype chain寻找,并一直到Object。如果没有找到则undefined。
因此实现继承最好不破坏这条链,但是MA的实现破坏了他,除了这点MA实现是很完美的。
下面的例子会形成PositionedRectangle,Rectangle,Object的prototype chain,但是Ma实现没有中间的Rectangle,这是Ma实现的缺点。
Prototype
Prototype是对象(文中(以前文也是)和Js关联的对象都是指objects,不同于Object或者c#中的对象,定义在ecma有)。
但是他和其他对象的区别是,Js会为其指定一个默认constructor,他指向和Prototype关联的构造函数。没有继承的情况下,一般都是默认值(除非手动修改),但继承的实现方式可能会改变Prototype类型。
如例子中:
加上:PositionedRectangle.prototype.constructor = PositionedRectangle;
pr.constructor.prototype instanceof Rectangle//ture
去掉:PositionedRectangle.prototype.constructor = PositionedRectangle;
pr.constructor.prototype instanceof Rectangle//false
注:但是我认为不要依赖prototype的类型做任何判断,象上面的判断应该都要避免,Js没有说明prototype类型,只保证是objct 就合法。这也是prototype和其他对象不同之处,别的对象可以依赖于instanceof。
继承的属性&重新生成的属性
继承在这有两种含义:prototype 继承和通常意义继承(在Definitive guide上称为子类化和超类化,没有称为继承)。
Call,apply的使用,转换了上下文,所以他们的属性已经不再属于基类,也就是父类成员被拷贝到了子类,这不是继承。
pr.hasOwnProperty('width')//true
被继承下来的只是prototype中的属性,但是prototype的第一个值是constructor,这也导致基类私有变量被继承。也就是说,基类私有变量在子类有两份,一份是拷贝过来的,另一份是继承下来的,虽然实际上copy过来的属性会隐藏继承下来的属性,我们一般不会访问到但是不是不能访问,这可能会是安全漏洞。例子中继承下来的变量可以这样访问:
PositionedRectangle.prototype.width;//undifiend
注:Ma实现只存在拷贝,不存在继承私有变量。
属性隐藏
本质就是通过prototypechain
第一种实现的副作用
我想要的只是prototype,结果一些无用的变量被继承,一些默认实现被修改,详细看代码注释。
Ma实现的副作用
破坏prototypechain,强制准确类型判断必须用反射。Prototypechain的改变使依赖于它的Js系统函数不能正确工作,如:instanceof
My.PositionedRectangle.prototype instanceof My.Rectangle//false
pr instanceof My.PositionedRectangle//false 不能正确判断基类
可以看到实现方式不同,继承会有不同的结果。如果不看源码,而用通常实现来理解Ma的继承,会产生误解。
Instanceof
我不知道是如何实现Instanceof函数的,但是可以推测他的实现,那就是可能用prototypechain
实现的类型识别,因为这是惟一可能回溯到基类的地方。这也是Ma的类型不能正确工作的原因。
类型辨别功能的缺失,是MA必须提供其他方式来判断来型,那就是“反射”,这里的反射也和C#没有一点关系,在Ma中应该优先用反射判断类型,这是唯一准确的方式。
反射
MA极大的改进了Js的类型识别,他也必须这样做,否则没有别的办法来识别类型。用的也很巧,只是在注册namespace或者类时做个记录,却实现了这么强的功能,Ms称为 Reflector。
如果不这样,用下面的实现检测类型,会不准确,也很笨拙:






























可以把上面的代码看作Ma中反射原形,虽然和MA实现不同,但都是基于给obj增加classname属性实现,MA的registerNamespace,registerclass解析了类型,是其他方法能工作的基础。
通常实现
摘自Definitive





























































































我加注释的版本,注释不是上面的翻译:

























































用MA库实现的版本:
Type.registerNamespace('My');

// Here is a simple Rectangle class.

// It has a width and height and can compute its own area

My.Rectangle= function(w, h) {

this.width = w;

this.height = h;

}

My.Rectangle.prototype.area = function( ) { return this.width * this.height; }

My.Rectangle.registerClass('My.Rectangle');


// Here is how we might subclass it

My.PositionedRectangle=function(x, y, w, h) {


My.PositionedRectangle.initializeBase(this,[w,h]);

// Now store the position of the upper-left corner of the rectangle

this.x = x;

this.y = y;

}


My.PositionedRectangle.prototype.contains = function(x,y) {

return (x > this.x && x < this.x + this.width &&

y > this.y && y < this.y + this.height);

}

My.PositionedRectangle.registerClass('My.PositionedRectangle',My.Rectangle);

var pr=new My.PositionedRectangle(1,2,3,4);

MicrosoftAjax.js实现



















































继承分成了两部分:registerClass,initialbase
代码执行过程不再分析,几个要点:


















接下来会写关于scope chain,callobject和闭包的,这些是Js中最头痛的概念,我用了一周才明白大概,可能是最后一篇,因为MA.js余下的东西都没有什么可说了