YUI 3中的两种不同继承模式
[翻译文章,原文来自:http://www.yuiblog.com/blog/2010/01/06/inheritance-patterns-in-yui-3/]
这篇文章讨论YUI 3 中实现的两种JavaScript代码重用模式――类型继承模式(classical inheritance pattern)和原型继承模式(prototypal inheritance pattern)。
需要的依赖(satisfied dependences)
原型继承模式作为YUI 3 核心API在”yui-min.js”种子文件中实现的。类型继承模式则需要”oop”模块。但是因为”oop”模块会被很多别的模块所使用,一般来说你不需要做额外引用来使用这个功能。如果你想自己创建一个简单的测试页面来试试这个模式,可以如下引用需要的模块
类型继承模式(classical inheritance pattern)
我们称类型继承模式为”经典模式”(classical)并不是因为它来自古埃及的柏拉图时代,而是因为这种模式可以帮助你以”类型”的方式思考问题。JavaScript没有类型,取而代之的是它有构造函数(constructor)。例如在Java或者其他语言中你可以定义”Programmer”类型并让它继承”Person”类型。但是,JavaScript中你能直接定义的是一个Programmer构造函数和一个Person构造函数。类型继承模式的目标就是让Programmer构造函数创建出来的对象可以继承由Person构造函数创建的属性 (properties) 和方法 (methods) 。
考虑下面两个构造函数:
// properties of the parent\’s prototype
Person.prototype.getName = function() { return this.name; };
// child constructor
function Programmer(){}
YUI 3中”oop”模块提供的”Y.extend(…)”方法能让你非常容易地实现类型继承模式:
现在你就可以如下测试”getName()”方法是否被正确继承下来:
注意”Y.extend(…)”方法只继承prototype中的成员,而不包括私有成员(“own” members)。所以,一个好的习惯就是把所有可重用的功能添加到prototype中,并且把所有和类型实例相关的属性定义为私有属性(“own” properties)。如上面例子,”getName()”被继承到Programmer中,而”name”则没有被继承(在后面要讨论到的原型继承模式中,”prototype”成员和”own”成员都会被继承)。
扩展与增强(extend and augment)
“Y.extend(…)”函数不仅可以让你继承父构造函数,同时还可以给子类添加新的成员。YUI这种用来扩展类的方式其实就是”de facto“模式。你可以利用”Y.extend(…)”函数的第三个参数在子类的”prototype”中添加属性,并且你可以用它的第四个参数给子类添加它自己的静态属性(class static properties)。下面就是一个扩展与增强的例子:
// groksHTML is now a property of the child\’s prototype
alert(typeof Programmer.prototype.groksHTML); // “boolean”
// the property works for all new objects
var bob = new Programmer();
alert(bob.groksHTML); // true
// adding to the constructor is more for
// “static” properties meant to act as constants
alert(Programmer.LIMIT); // “sky”
var limit = bob.LIMIT; // undefined
父类(superclass)
YUI3的类型继承模式还提供了一个静态属性――superclass—让你访问父类构造函数的prototype。因为”supperclass”指向父类构造函数的prototype,所以”superclass.custructor”就指向父类的构造函数。如下列:
// child\’s access to the parent constructor
var parent = Programmer.superclass.constructor;
// test
alert(parent === Person); // true
// access to the parent from an instance of the child
var guru = new Programmer();
guru.constructor.superclass.constructor === Person; // true
如前所说,经典继承模式只能继承prototype成员。但是通过使用”superclass”,你可以在子类中调用父类的构造器。这样你就把父类的私有属性(own properties)变成子类的私有属性(own properties)。例如,你可以在Programmer构造器中调用父类构造器,传入子类实例(this)和任何初始化参数:
// inheritance
Y.extend(Programmer, Person);
// test
var pro = new Programmer();
alert(pro.name); // “Adam”
如例所见,”Programmer”实例现在就有”name”属性,并且它是一个私有属性(own property):
访问重置方法(access to overridden methods)
因为”superclass”指向父类构造函数的prototype,这给我们提供了一个访问重置方法的途径。考虑下面这个经典例子(Triangle继承自Shape):
// child
function Triangle(){}
// inheritance
Y.extend(Triangle, Shape);
// child overrides the parent\’s toString() method
// but thanks to the superclass property
// it still has access to the original method
Triangle.prototype.toString = function(){
return Triangle.superclass.toString() + “, triangle”;
};
// test
var acute = new Triangle();
acute.toString(); “shape, triangle”
原型继承模式(Prototypal inheritance pattern)
Douglas Crockford 推荐这种继承模式。该模式剔除所有类型的概念,让你直接从一个实例继承出另外一个实例。例如:
// the inheritance magic
// a new object is born from an existing one
var batman = Y.Object(parent);
// customize or augment the new object
batman.name = “Bruce”;
// use
batman.say(); // I am Bruce Wayne
你通过下面两步来使用这个模式:
- 创建一个新的对象,它继承一个已存在对象的所有属性和方法。
- 扩展(customize)这个新的对象――你可以覆盖一些继承来的成员或者添加新的成员。
注意:”Y.Object(…)”包含在YUI核心库中。你不需要应用”oop”模块
原型继承讨论
如果你对原型继承模式后面动机和低层实现机制感兴趣,可以参考Douglas Crockford他自己对这个模式的描述。使用这个模式时,父类的成员通过”prototype”链继承下来的。这就意味着如果子类添加了一个与父类同名的属性,子类属性不会覆盖从父类继承来的那个属性,但是它会拥有优先访问权。换句话说,你可以如下重新定义上面例子中的”say”方法:
// test
batman.say(); // “Can\’t tell you my real name”
与Y.extend(…)函数提供的类型继承模式所不同,原型继承模式无法提供类似与”superclass”属性来访问父类的”say”方法。但是,如果你删除(delete)子类的”say”方法后,父类的方法就露出来。如下:
在ECMAScript标准最新版本中,它提供一个native方法”Object.create(…)”来支持原型继承模式:
// ECMAScript 5 (future)
var batman = Object.create(parent);
更多资源
谢谢你的阅读!关于这两个模式的更多信息和例子,你可以参考下面的链接: