13

前言

我们学JAVA的时候说到继承就是一个extends ClassName的事情,但是在JS的世界里继承和我们在JAVA所认识的继承实现方法又有一些不同,你们真的了解JS的继承吗?就当你们很了解了,毕竟是基础知识,我就简单说说

原型链继承

简言之就是把被继承的对象赋值给继承者的原型对象

function Super() {
    this.name = 'mirok';
}
Super.prototype.showName = function () {
    console.log(this.name);
}
function Sub() {
    this.name = 'july';
}
Sub.prototype = new Super();
const obj = new Sub();
obj.showName(); //输出july

原型实现继承虽然可以,但是也有相应的弊端,例如new Super()构建多个实例,继承里面的方法被其中一个实例重写,就会影响其他实例,也就是说原型里的是所有实例所共享的,这是我们不愿看到的,因此就有以下的方法。

借用构造函数

简言之就是在继承者的构造函数中去调用被继承者的构造函数(即使用apply()/call()实现)

function Super() {
    this.supername = 'mirok';
}
function Sub() {
    Super.call(this)
    this.name = 'july';
}
Sub.prototype = new Super();
const obj = new Sub();
obj.name; //july
obj.supername; //mirok

这种方式实现的继承相对于之前的来说不仅解决了之前的问题还能向被继承者传参数,但是也有一定的弊端,即容易覆盖本身的属性,解决方法就是在调用被继承者的构造函数再对自己添加属性,也就是说上面的Super.call要在this.name定义属性之前。另一个弊端就是继承的是无法共享的

组合继承

这个就是组合前面的原型链继承和借用构造函数继承两者之长,也就是说既能在继承后的实例都有一份属性又能共用

function Super() {
    this.name = 'mirok';
}
Super.prototype.showName = function () {
    console.log(this.name);
}
function Sub1() {
    Super.call(this);
    this.name = 'july';
}
function Sub2() {
    Super.call(this);
    this.name = 'deny';
}
Sub1.prototype = new Super();
Sub2.prototype = new Super();
const obj1 = new Sub1();
const obj2 = new Sub2();
obj1.showName(); // july
obj2.showName(); // deny

原型式继承

这个比较特殊一点,就是在一个函数里去做原型链继承的事情

function object(obj) {
    function fun() {};
    fun.prototype = obj;
    return new fun();
}

ES5规范了这类写法,就是Object.create(),但是弊端和第一种类似,因为不是我们理想的继承这里就不详细介绍

寄生式继承

这个也比较特殊,就是把继承的事情放在一个函数里去做,再把对象返回

function object(obj) {
    function fun() {};
    fun.prototype = obj;
    return new fun();
}
function factory() {
    const person = {name:'mirok', age: 22};
    const obj = object(person);
    obj.show = function() {console.log(this.name)}
    return obj;
}
factory().show(); //'mirok'

至于弊端可见而知,不能实现共享

寄生组合式继承

组合继承有个弊端就是会调用两次被继承者的构造函数,解决方法就是使用寄生组合式继承。这又是什么呢?这个相对之前的比较复杂,但是高效的一点是只调用一次被继承者构造函数,原理就是通过寄生方式创建一个被继承者的副本,副本和被继承者共用一个prototype,这样就解决了之前的问题

function object(obj) {
    function fun() {};
    fun.prototype = obj;
    return new fun();
}
function factory(Sub, Super) {
    var proto = object(Super.prototype); //返回Super的一个副本
    proto.constructer = Sub; //设置constructor指向, 因为新副本的原型对象被重写
    Sub.prototype = proto; //副本作为sub的原型对象
}
function Super () {
    this.name = 'july';
}
Super.prototype.show = function () {
    console.log(this.name);
}
function Sub1 () {
    Super.call(this);
    this.name = 'mirok'
}
function Sub2 () {
    Super.call(this);
    this.name = 'deny'
}
factory(Sub1, Super);
factory(Sub2, Super);
var obj1 = new Sub1();
var obj2 = new Sub2();
obj1.show(); // mirok
obj2.show(); // deny

flayPig
460 声望379 粉丝

attemp to do something that is defferent.