乐趣区

JS-面向对象编程-继承

继承

类式继承

// 类式继承
// 声明父类
function SuperClass() {this.superValue = true;}
// 为父类添加共有方法
SuperClass.prototype.getSuperValue = function() {return this.superValue;}
// 声明子类
function SubClass() {this.subValue = false;}
// 继承父类
SubClass.prototype = new SuperClass();
// 为子类添加共有方法
SubClass.prototype.getSubValue = function() {return this.subValue;}

???? 缺点

  • 由于子类通过其原型 prototype 对父类实例化,继承了父类。如果父类中的共有属性为引用类型,就会在子类中被所有实例共用,因此一个子类的实例更改子类的原型从父类构造函数中继承来的共有属性就会直接影响到其他子类
  • 由于子类通过其原型 prototype 对父类实例化实现的,因此在创建父类的时候,是无法向父类传递参数的,因而在实例化父类的时候也无法对父类构造函数内的属性进行初始化

构造函数继承

// 构造函数式继承
// 声明父类
function SuperClass(id) {
    // 引用类型共有属性
    this.books = ['js', 'html', 'css'];
    // 基本类型共有属性
    this.id = id;
}
// 父类声明原型方法
SuperClass.prototype.showBooks = function() {console.log(this.books);
}
// 声明子类
function SubClass() {
    // 继承父类
    SuperClass.call(this, id);
}
// 创建第一个子类的实例
var instance1 = new SubClass(10);
// 创建第二个子类的是咧
var instance2 = new SubClass(20);

instance1.books.push('设计模式');
console.log(instance1.books); // ['设计模式', 'js', 'html', 'css']
console.log(instance1.id); // 10
console.log(instance2.books); // ['js', 'html', 'css']
console.log(instance2.id); // 20

instance1.showBooks(); // TypeError

???? 缺点

  • 这种类型的继承没有涉及原型 prototype,所以父类的原型方法不会被子类继承

组合继承

// 组合继承
// 声明父类
function SuperClass(name) {
    // 引用类型共有属性
    this.books = ['js', 'html', 'css'];
    // 基本类型共有属性
    this.name = name;
}
// 父类原型共有方法
SuperClass.prototype.getName = function() {console.log(this.name);
}
// 声明子类
function SubClass(name, time) {
    // 继承父类
    SuperClass.call(this, name);
    // 子类中新增共有属性
    this.time = time;
}
// 类式继承 子类原型继承父类
SubClass.prototype = new SuperClass();
// 子类原型方法
SubClass.prototype.getTime = function() {console.log(this.time);
}

var instance1 = new SubClass('js book', 2020);
instance1.books.push('设计模式');
console.log(instance1.books); // ['js', 'html', 'css', '设计模式']
instance1.getName(); // 'js book'
instance1.getTime(); // 2020

var instance2 = new SubClass('css book', 2021);
console.log(instance2.books); // ['js', 'html', 'css']
instance2.getName(); // 'css book'
instance2.getTime(); // 2021

???? 缺点

  • 这种继承方式在使用构造函数继承时执行了一遍父类的构造函数,而在实现子类原型的类式继承时又调用了一边父类构造函数

原型式继承

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

???? 缺点

  • 与类式继承一样,父类中引用类型的属性被共用

寄生式继承

// 寄生式继承
// 声明基对象
var book = {
    name: 'js book',
    alikeBook: ['css book', 'html book'],
}
function createBook(obj) {
    // 通过原型继承方式创建新对象
    var o = new inheritObject(obj);
    // 拓展新对象
    o.getName = function() {console.log(this.name);
    }
    // 返回拓展后的新对象
    return o;
}

???? 缺点

  • 与类式继承一样,父类中引用类型的属性被共用

寄生组合式继承

/**
  * 寄生式继承 继承原型
    * 传递参数 subClass 子类
    * 传递参数 superClass 父类
    **/
function inheritPrototype(subClass, superClass) {
    // 复制一份父类的原型副本保存在变量中
    var p = inheritObject(superClass.prototype);
    // 修正因为重写子类原型导致子类的 constructor 属性被修改
    p.constructor = subClass;
    // 设置子类的原型
    subClass.prototype = p;
}

// 定义父类
function SuperClass(name) {
    this.name = name;
    this.color = ['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', 2020);
var instance2 = new SubClass('css book', 2021);

???? 缺点

  • 子类添加原型方法必须通过 prototype. 对象 ,通过点语法的形式一个一个添加方法,否则直接赋予对象就会覆盖掉从父类原型继承的对象
退出移动版