谈谈JS中的继承(二)

90 阅读2分钟

距离上一次发布继承的文章已经很久了,今天继续来分析下其他的更优的解决方案

原型式继承

先看下实现方式

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

是不是发现和类式继承有点像?

  • 过渡函数F相当于类式继承中的子类,在原型式继承中的目的是返回一个实例化对象
  • 类式继承的缺点在原型式继承中也存在
  • 但是由于过渡构造函数函数F中无内容,所以开销小一点
  • 也可以使用闭包把F缓存起来

Object.create()就是在这种继承的思想下出现的

使用一下子类


const book = {
  name: "js Book",
  alikeBook: ["CSS", "HTML"],
};

var newBook = inherit(book);

newBook.name = "ajax Book";
newBook.alikeBook.push("xml");

var otherBook = inherit(book);
otherBook.name = "flash Book";
otherBook.alikeBook.push("as book");

// "ajax Book"
console.log(newBook.name);
//["CSS","html","xml","as book"] 🎈🎈🎈
console.log(newBook.alikeBook);

// "flash Book"
console.log(otherBook.name);
//["CSS","html","xml","as book"]🎈🎈🎈🎈
console.log(otherBook.alikeBook);

// "js Book"
console.log(book.name);
//["CSS","html","xml","as book"]🎈🎈🎈🎈🎈
console.log(book.alikeBook);

寄生式继承

先来看实现

const book = {
  name: "js Book",
  alikeBook: ["CSS", "HTML"],
};
function createBook(obj) {
    // 原型式继承
    var o = new inherit(obj)
    
    // 拓展新对象
    o.getName = function () {
        console.log(this.name)
    }
    // 返回拓展后的新对象
    return o
}

寄生式继承就是对原型继承的第二次封装

  • 在封装过程中对继承的对象进行拓展这样新创建的对象不仅仅有父类中的属性和方法和可以添加新的属性和方法
  • 原型继承的缺点仍然存在

寄生组合式继承(圣杯模式)

看标题是不是猜到的大概,就是将寄生式继承构造函数继承结合起来

上代码

function inheritPrototype(SubClass, SupperClass) {
  var p = inherit(SupperClass.prototype);
  p.constructor = SubClass;
  SubClass.prototype = p;
}

function SupperClass(name) {
  this.name = name;
  this.colors = ["red"];
}

SupperClass.prototype.getName = function () {
  console.log(this.name);
};

function SubClass(name) {
  SupperClass.call(this, name);
  this.time = "123";
}

inheritPrototype(SubClass, SupperClass);

SubClass.prototype.getTime = function () {
  console.log(this.time);
};

var ins1 = new SubClass("ins1");
var ins2 = new SubClass("ins2");
ins1.colors.push("black");

console.log(ins1);
console.log(ins2);


/**
 * 
 * {
    "name": "ins1",
    "colors": [
        "red",
        "black"
    ],
    "time": "123"
}

{
    "name": "ins2",
    "colors": [
        "red"
    ],
    "time": "123"
}
 */

解决了共有引用类型污染问题,同时也因为构造函数继承是的具有初始化父类构造函数属性的功能

好了 这就是关于在ES5中关于继承的实现,可以帮我们更好的理解js中原型链