JS - 继承及设计模式

相关连接

文章待补充部分:

  • 代理模式

    • 考虑图片延迟加载方案
    • 考虑多次点击一次请求方案
  • 享元模式

    • alloy-team一个很好的例子,有1000个朋友,但同时只需要显示10个朋友。只需要做一个包含10个用户的数组,当向下滚动一个,数组就从头删除一个,尾部加一个
    • 事件委托也是用了享元模式 Javascript设计模式理论与实战:享元模式,

构造函数继承

new缺陷是不能共享属性

 function DOG(name){
    this.name = name;
 }
var dogA = new DOG('大毛');
alert(dogA.name); // 大毛 

原型链继承

  function DOG(name){
    this.name = name;
  }
  DOG.prototype = { species : '犬科' };

  var dogA = new DOG('大毛');
  var dogB = new DOG('二毛');

  alert(dogA.species); // 犬科
  alert(dogB.species); // 犬科

多重继承

利用call:

var s1 = function(name){
this.name = name;
}

var s2 = function(sex){
this.sex = sex;
}

var s3 = function(age){
this.age = age;
}

var Student = function(name, sex, age, score){
s1.call(this, name);
s2.call(this, sex);
s3.call(this, age);
this.score = score;
}
Student.prototype.constructor = Student;

var s = new Student('jack', 'male', '12', '100');
alert(s.name);//jack
alert(s.sex);//male
alert(s.age);//12
alert(s.score);//100

这样我们就可以根据各个不同的功能模块分不同程序员独立开发,最后合并起来,实现了多重继承。
当然如果参数过多的话可以使用object参数来做。而且各个功能模块耦合度比较小,出现BUG也能很快定义到功能模块,修改其中某一个对其他没有影响。

多层继承

var s1 = function(){}
s1.prototype.getName = function(){alert(this.name)};

var s2 = function(){}
// 注意此处为new s1(),不能是s1
s2.prototype =new s1();
s2.prototype.constructor = s2;
s2.prototype.getSex = function(){alert(this.sex)};

var s3 = function(){}
s3.prototype = new s2();
s3.prototype.constructor = s3;
s3.prototype.getAge = function(){alert(this.age)};

var s = new s3();
s.name = 'jack';
s.sex = 'male';
s.age = '22';

s instanceof s3
//true
s instanceof s2
// true
s instanceof s1
// true

另:prototype继承补充

可通过es5 object.create()实现原型链继承:
Object.create()
下面的例子演示了如何使用Object.create()来实现类式继承。这是一个所有版本JavaScript都支持的单继承。

// Shape - 父类(superclass)
function Shape() {
  this.x = 0;
  this.y = 0;
}

// 父类的方法
Shape.prototype.move = function(x, y) {
  this.x += x;
  this.y += y;
  console.info('Shape moved.');
};

// Rectangle - 子类(subclass)
function Rectangle() {
  Shape.call(this); // call super constructor.
}

// 子类续承父类
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;

// 因为使用“.prototype =...”后,constructor会改变为“=...”的那个
// constructor,所以要重新指定.constructor 为自身。

var rect = new Rectangle();

console.log('Is rect an instance of Rectangle?',
  rect instanceof Rectangle); // true
console.log('Is rect an instance of Shape?',
  rect instanceof Shape); // true
rect.move(1, 1); // Outputs, 'Shape moved.'

单体模式

  • 可以来划分命名空间,从而清除全局变量所带来的危险。
  • 利用分支技术来来封装浏览器之间的差异。
  • 可以把代码组织的更为一体,便于阅读和维护。
/*Basic Singleton*/
var Singleton = {
    attribute:true,
    method1:function(){},
   method2:function(){}
};

如果你希望能继承到多个对象,则可以使用混入的方式。

function MyClass() {
     SuperClass.call(this);
     OtherSuperClass.call(this);
}

// 继承一个类
MyClass.prototype = Object.create(SuperClass.prototype);
// 混合其它
Object.assign(MyClass.prototype, OtherSuperClass.prototype);
// 重新指定constructor
MyClass.prototype.constructor = MyClass;

MyClass.prototype.myMethod = function() {
     // do a thing
};

var a = new MyClass();
a instanceof MyClass; // true
a instanceof SuperClass; // true
a instanceof OtherSuperClass; // false

Object.assign 会把 OtherSuperClass原型上的函数拷贝到 MyClass原型上,使 MyClass 的所有实例都可用 OtherSuperClass 的方法。Object.assign 是在 ES2015 引入的.
测试assign方法后,如new一个实例,发现实例并不是OtherSuperClass的子类,原因是assign是做了属性复制,并没有将OtherSuperClass加入到原型链当中

简单工厂模式

简单工厂模式:使用一个类,通常为单体,来生成实例。

var XMLHttpFactory =function(){};      //这是一个简单工厂模式
  XMLHttpFactory.createXMLHttp =function(){
    var XMLHttp = null;
    if (window.XMLHttpRequest){
      XMLHttp = new XMLHttpRequest()
    }else if (window.ActiveXObject){
      XMLHttp = new ActiveXObject("Microsoft.XMLHTTP")
    }
  return XMLHttp;
  }
  //XMLHttpFactory.createXMLHttp()这个方法根据当前环境的具体情况返回一个XHR对象。
  var AjaxHander =function(){
    var XMLHttp = XMLHttpFactory.createXMLHttp();
    ...
  }

复杂工厂模式

复杂工厂模式定义是:将其成员对象的实列化推到子类中,子类可以重写父类接口方法以便创建的时候指定自己的对象类型。
父类只对创建过程中的一般性问题进行处理,这些处理会被子类继承,子类之间是相互独立的,具体的业务逻辑会放在子类中进行编写。

var XMLHttpFactory =function(){};      //这是一个抽象工厂模式

XMLHttpFactory.prototype = {
  //如果真的要调用这个方法会抛出一个错误,它不能被实例化,只能用来派生子类
  createFactory:function(){
    throw new Error('This is an abstract class');
  }
}

var XHRHandler =function(){}; //定义一个子类
// 子类继承父类原型方法
extend( XHRHandler , XMLHttpFactory );
XHRHandler.prototype =new XMLHttpFactory(); //把超类原型引用传递给子类,实现继承
XHRHandler.prototype.constructor = XHRHandler; //重置子类原型的构造器为子类自身

//重新定义createFactory 方法
XHRHandler.prototype.createFactory =function(){
  var XMLHttp =null;
  if (window.XMLHttpRequest){
    XMLHttp =new XMLHttpRequest();
  }else if (window.ActiveXObject){
    XMLHttp =new ActiveXObject("Microsoft.XMLHTTP")
  }
  return XMLHttp;
}

单例模式

单例模式定义了一个对象的创建过程,此对象只有一个单独的实例,并提供一个访问它的全局访问点。也可以说单例就是保证一个类只有一个实例,实现的方法一般是先判断实例存在与否,如果存在直接返回,如果不存在就创建了再返回,这就确保了一个类只有一个实例对象。

var single = (function(){
    var unique;

    function getInstance(){
    // 如果该实例存在,则直接返回,否则就对其实例化
        if( unique === undefined ){
            unique = new Construct();
        }
        return unique;
    }

    function Construct(){
        // ... 生成单例的构造函数的代码
    }

    return {
        getInstance : getInstance
    }
})();

观察者模式(发布订阅模式)

常用的事件监听,创建listener,addListener,trigger,removeListens几项,当trigger触发时,则读取listener中存储的函数,以此执行。实现监听模式

链接

@2017-11-19 22:53