基于原型的类继承
我们之前已经提到过prototype 属性很多次了,但还没有正儿八经地解释过它。现在我们来详细讲解什么是原型,以及如何用它来实现类的继承。
JavaScript 是基于原型的编程语言,原型用来区别类和实例,这里提到一个概念:原型对象(prototypical object)。原型是一个“模板”对象,它上面的属性被用做初始化一个新对象。任何对象都可以作为另一个对象的原型对象,以此来共享属性。实际上,可以将其理解为某种形式的继承。
当你读取一个对象的属性时,JavaScript 首先会在本地对象中查找这个属性,如果没有找到,JavaScript 开始在对象的原型中查找,若仍未找到还会继续查找原型的原型,直到查找到Object.prototype。如果找到这个属性,则返回这个值,否则返回undefined。
换句话说,如果你给Array.prototype 添加了属性,那么所有的JavaScript 数组都具有了这些属性。
广州网站建设,广州网站设计,广州网站制作,网站建设,网站设计,广州网站建设公司,广州网站设计公司
为了让子类继承父类的属性,首先需要定义一个构造函数。然后,你需要将父类的新实例赋值给构造函数的原型。代码如下:
- var Animal = function(){};
- Animal.prototype.breath = function(){
- console.log('breath');
- };
- var Dog = function(){};
- // Dog 继承了Animal
- Dog.prototype = new Animal;
- Dog.prototype.wag = function(){
- console.log('wag tail');
- };
现在我们来检查一下继承是否生效了:
- var dog = new Dog;
- dog.wag();
- dog.breath(); // 继承的属性
给“类”库添加继承
现在来给我们自定义的“类”库添加继承,我们通过传入一个可选的父类来创建新类:
- var Class = function(parent){
- var klass = function(){
- this.init.apply(this, arguments);
- };
- // 改变klass 的原型
- if (parent) {
- var subclass = function() { };
- subclass.prototype = parent.prototype;
- klass.prototype = new subclass;
- };
- klass.prototype.init = function(){};
- // 定义别名
- klassklass.fn = klass.prototype;
- klassklass.fn.parent = klass;
- klassklass._super = klass.__proto__;
- /* include/extend 相关的代码…… */
- return klass;
- };
如果将parent 传入Class 构造函数,那么所有的子类则必然共享同一个原型。这种创建临时匿名函数的小技巧避免了在继承类的时候创建实例,这里暗示了只有实例的属性才会被继承,而非类的属性。设置对象的__proto__; 属性并不是所有浏览器都支持,类似Super.js(http://github.com/maccman/super.js)的类库则通过属性复制的方式来解决这个问题,而非通过固有的动态继承的方式来实现。
现在,我们可以通过给Class 传入父类来实现简单的继承:
- var Animal = new Class;
- Animal.include({
- breath: function(){
- console.log('breath');
- }
- });
- var Cat = new Class(Animal)
- // 用法
- var tommy = new Cat;
- tommy.breath();