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(sub, super){ var F = function(){}; F.prototype = superClass.prototype; sub.prototype = new F(); // step 2 sub.prototype.constructor = sub; // step3 }
这种展示了封装的原理,但是step1并没有封装进来,而最重要的是step1中会产生对Person的耦合。
高级封装extend函数继承
function extend(sub, super){ var F = function(){}; F.prototype = superClass.prototype; sub.prototype = new F(); // step 2 sub.prototype.constructor = sub; // step3 sub.super = super.prototype; // step 1 if(super.prototype.constructor == Object.prototype.constructor){ super.prototype.constructor = super; } }
这样在构建子类的构造函数时示例如下:
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]; } } } }
上面的方法还可以指明只继承其中的部分成员。
掺元类的重大有点就是可以实现多继承效果,其他的方法就没法了,因为一个对象只能有一个原型对象。
摘要: 类式继承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...阅读全文
摘要: 封装、信息隐藏与接口的关系信息隐藏是目的,封装是手段。接口提供了一份记载着可供公共访问的方法的契约。它定义了两个对象间可以具有的关系。只要接口不变,这个关系的双方都是可以替换的。一个理想的软件系统应该为所有类定义接口。创建对象的基本模式1.门户大开型var Publication = new Interface('Publication', ['getIsbn', 'setIsbn',...]); //接口var Book = function(isbn, title, author){ this.setIsbn(isbn); this.setT阅读全文
摘要: 什么是接口接口提供了一种用以说明一个对象应该具有哪些方法的手段。接口之利1.接口具有自我描述性从而促进代码的重用2.接口有助于稳定不同中的类之间的通信方式3.测试和调试也变得更轻松接口之弊1.在一定程度上强化了类型的作用2.js中没有内置的interface,实现它会增加复杂度3.实现接口会对性能造成一定的影响4.无法强迫其他程序员遵守你定义的接口三种方法在js中模仿接口注释法(这只是一种文档规范)/*interface Composite{ function add(child); function remove(child); function getChild(inde...阅读全文
摘要: 创建支持链式调用的类(构造函数+原型)Function.prototype.method = function(name, fn){ this.prototype[name] = fn; return this;};//构造函数+原型 创建类var Anim = function(){};Anim.method('starts', function(){ console.log('starts');}).method('ends', function(){ console.log('ends');});var a = new An阅读全文
分类: JS设计模式