JavaScript设计模式学习心得四

心得三说到组合继承,并不是我们需要的最完美的继承方式,那么什么方式更好呢?当然我们先做一些铺垫。
原型式继承

//原型式继承
function inheritObject(o){
    //声明一个过度函数对象
    function F(){}
    //过渡函数对象的原型继承父对象
    F.prototype = o;
    //返回过渡对象的一个实例,该实例的原型继承了父对象
    return new F();
}

//测试代码
var book = {
    name : "CSDN",
    alikeBooks : ["JavaScript","html"]
}
var newBook = inheritObject(book);
var otherBook = inheritObject(book);
newBook.name = "ajax book";
newBook.alikeBooks.push("PHP");
otherBook.name = "flash book";
console.log(newBook.name);  //ajax book
console.log(newBook.alikeBooks);    //["JavaScript","html","PHP"]
console.log(otherBook.name);    //flash book
console.log(otherBook.alikeBooks)   //["JavaScript","html","PHP"]
console.log(book.name);     //CSDN
console.log(book.alikeBooks);    //["JavaScript","html","PHP"]

这看着怎么跟类式继承有点像呢?感觉就是将类式继承封装了一下,并没有做其他操作,那么很明显,类式继承的一些缺点原型式继承也会有,就像上面的测试代码一样,父对象book中的值类型的属性被复制,引用类型的属性被共用。当然这并不是我们想要的,这只是个铺垫。
寄生式继承

//寄生式继承
function createBook(obj){
    //通过原型继承方式创建新对象,这里的inheritObject就是原型式继承中的函数
    var o = new inheritObject(obj);
    //拓展新对象
    o.getName = function(){
        console.log(name);
    }
    //返回拓展后的新对象
    return o;
}

这种方式式将原型式继承又套了一层封装,并且在第二次封装的过程中对继承的对象就行了拓展,那么缺点也是和原型式继承相同,没什么好说的,这只是一个过渡,来看下一种方式。
寄生组合式继承

//寄生式继承
//参数:subClass子类,superClass父类
function inheritPrototype(subClass, superClass){
    //复制一份父类的原型副本保存在变量中
    //此处的inheritObject()是原型继承中的,但传入的参数不是父类,而是父类的原型
    var p = inheritObject(superClass.prototype);
    //修正因为重写子类原型导致子类的constructor属性被修改
    p.constructor = subClass;
    //设置子类的原型
    subClass.prototype = p;
}
//定义父类
function SuperClass(name){
    this.name = name;
    this.colors = ["red","blue","green"];
}
//定义父类原型方法
SuperClass.prototype.getName = function(){
    console.log(this.name);
}
//定义子类
function SubClass(name, time){
    //构造函数式继承
    SuperClass.call(this,name);
    //子类新增属性
    this.time = time;
}
//寄生式继承父类原型
inheritPrototype(SubClass, SuperClass);
//子类新增原型方法(这个一定要写在继承后面,不然实现继承时会覆盖掉这个方法)
SubClass.prototype.getTime = function(){
    console.log(this.time);
}

//测试代码
var instance1 = new SubClass("js book",2014);
var instance2 = new SubClass("css book",2013);
instance1.colors.push("black");
console.log(instance1.colors);  //["red","blue","green","black"]
console.log(instance1.getName());   //js book
console.log(instance1.getTime());   //2014
console.log(instance2.colors);  //["red","blue","green"]
console.log(instance2.getName());   //css boook
console.log(instance2.getTime());   //2013

我们分析分析,上面的代码我们看到子类中是使用了构造函数继承的方式继承了父类,但是仅仅用这一种方式是无法继承到父类的原型对象的,但是又不能采用类式继承那种再一次调用父类的构造函数的方式。换句话说,在构造函数继承中我们已经调用了父类的构造函数,因此我们需要的只是父类的原型对象的一个副本,而这个副本我们通过原型式继承便可得到,但是这么直接赋值给子类会有问题,因为代码中p = inheritObject(superClass.prototype)这个副本对象p中的constructor指向的不是SubClass子类对象(默认情况下javascript中函数的prototype.constructor是指向函数本身),因此在将p赋值给子类原型之前,我们需要纠正一下constructor的指向,这才有了p.constructor = subClass。这样子类的原型就继承了父类的原型,并且没有执行父类的构造函数。
这种继承的方式最大的特点就是将子类原型被赋予父类原型的一个引用,这是一个对象,因此这里要注意一点,就是子类再想添加原型方法必须通过prototype.对象,通过点语法的形式一个一个添加方法了,否者直接赋予对象就会覆盖掉从父类原型继承的对象了。
再附上一张上面代码的继承原理图。
JavaScript设计模式学习心得四_第1张图片

你可能感兴趣的:(day)