JS设计模式——4.继承(概念)
类式继承
0.构造函数
一个简单的Person类
function Person(name){ this.name = name; } Person.prototype.getName = function(){ return this.name; }
1.原型链实现继承
未封装extend函数继承
继承步骤如下:
step 1:创建继承类的构造函数
step 2:设置继承类的原型链为父类构造函数。
step 3:调整继承类的构造函数。
step 4:创建继承类
function Author(name, books){ Person.call(this, name); //step 1 this.books = books; } Author.prototype = new Person(); //step 2 Author.prototype.constructor = Author; // step 3 Author.prototype.getBooks = function(){ return this.books; }; var author = new Author('ysy',['js desgin']); // step 4
简单封装extend函数继承
function extend(subClass, superClass){ var F = function(){}; F.prototype = superClass.prototype; subClass.prototype = new F(); // step 2 subClass.prototype.constructor = subClass; // step3 }
这种展示了封装的原理,但是step1并没有封装进来,而最重要的是step1中会产生对Person的耦合。
高级封装extend函数继承
function extend(subClass, superClass){ var F = function(){}; F.prototype = superClass.prototype; subClass.prototype = new F(); subClass.prototype.constructor = subClass; subClass.superclass = superClass.prototype; if(superClass.prototype.constructor == Object.prototype.constructor){ superClass.prototype.constructor = superClass; } }
这样在构建子类的构造函数时示例如下:
function Author(name, books){ Author.superclass.constructor.call(this, name); this.books = books; } extend(Author, Person);
原型式继承
0.原型对象
直接定义一个对象即可
var Person = { name: 'ysy', getName: function(){ return this.name; } }
1.对继承而来的成员的读和写的不对等性
这个其实很好理解,如果在读属性之前还未对继承而来的属性进行赋值操作,那么读的就是super中的属性,而此时写的话,却是对sub中的写。
当然,一旦写过之后,读和写就是对等的了。
这个简单问题就不再给出代码了。如果你不懂,就去彻底了解一下原型链。
2.clone函数
function clone(obj){ function F(){} F.prototype = obj; return new F; }
3.继承的实现
var Author = clone(Person); Author.books = []; Author.getBooks = function(){ return this.books; }
貌似这个继承的实现要简单好多哇。
继承与封装
只有公用和特权成员会被继承下来。
因此,门户大开型式最适合派生自雷的。它们的所有成员都是公开的,因此可以被遗传给子类。如果某个成员需要稍加隐藏,可以用下划线规范。
在派生具有真正的私有成员的类时,特权方法是公用的,可以被继承,因此也就可以访问父类的私有成员,但是我们不能在子类中添加能够直接访问他们的新的特权方法。
掺元类
有一种重用代码的方法不需要用到严格的继承。
他的做法是:先创建一个包含各种通用方法的类,然后再用他扩充其他类。
这种包含通用方法的类就是掺元类。
下面定义一个简单的掺元类:
var Mix = function(){}; Mix.prototype = { serialize: function(){ var output = []; for(key in this){ output.push(key+':'+this[key]); } return output.join(','); } } augment(Author, Mix); var author = new Author('Ross', ['js desgin']);
augment其实很简单。他用一个for in将giving class的prototype中的每个成员都添加到receiving class中。
function augment(rclass, gclass){ if(arguments[2]){ //giving more than 3 paras for(var i=2, len=arguments.length; i<len; i++){ rclass.prototype[arguments[i]] = gclass.prototype[arguments[i]]; } }else{ for(methodName in gclass.prototype){ if(!rclass.prototype[methodName]){ rclass.prototype[methodName] = gclass.prototype[methodName]; } } } }
上面的方法还可以指明只继承其中的部分成员。
掺元类的重大有点就是可以实现多继承效果,其他的方法就没法了,因为一个对象只能有一个原型对象。