JavaScript 继承

原型链继承

function Parent2() {
  this.name = "parent2";
  this.play = [1, 2, 3];
}
function Child2() {
  this.type = "child2";
}
Child2.prototype = new Parent2();

let child1 = new Child2();
let child2 = new Child2();

child1.play.push(4);
child1.name='child1'; // 该行为是往 child1 上添加name属性,并不会查找

console.log(child2.name) // "parent2",
console.log(child1.play, child2.play);

缺点

  • 需要手动修改 constructor 指向
  • 无法调用父类的构造函数传参
  • 多个子实例的原型都是指向同一个对象,容易造成污染
    在这里插入图片描述

构造继承

  • Parent1.call(this);会调用Parent方法,将属性绑定到child1上
function Parent1() {
  this.name = "parent1";
  this.f = function () {
    console.log("parent1");
  };
}
function Child1() {
  Parent1.call(this);
  this.type = "child1";
}

let child = new Child1();
child.f();

优点

  • 解决了原型链继承中多个子实例的原型都是指向同一个对象,容易造成污染的问题
  • 不需要手动修改 constructor 指向
  • 可以通过 instanceof 判断来源

缺点

  • 因为没有 new 操作无法继承 Parent 原型上的内容
  • child 并不算 Parent 真正的子类,通过 instanceof 无法判断
  • 根据调用位置可能覆盖子实例的属性,不以子实例属性优先
function Child () {
  this.sex = 'boy'
  this.name = 'bad boy'
  Parent.call(this, 'good boy')  // 如果 Parent 内也有 this.name,最终 child.name="good boy"
}

组合继承

  • 解决上一步实例属性污染的问题
function Parent (name) {
  console.log(name) // 这里有个console.log()
  this.name = name
}
Parent.prototype.colors=['red'];

function Child (name) {
  Parent.call(this, name)
}
Child.prototype = new Parent()
Child.prototype.constructor = Child;

var child1 = new Child('child1')

优点

  • 继承父类原型上的属性和方法
  • 父类非原型上的属性和方法隔离

缺点

  • 多个子实例的原型都是指向同一个对象,如果子实例修改了父类原型上的属性,会造成污染,但如果修改的是父类非原型上的属性和方法则不会,因为已经复制了一遍到子实例上
  • Parent.call(this, name)、new Parent() 会造成父类构造函数调用两次
  • 需要手动修改 constructor 指向

寄生组合继承(推荐,和 extends 继承效果一致)

function Parent5() {
  this.name = "parent5";
  this.play = [1, 2, 3];
}
function Child5() {
  Parent5.call(this);
  this.type = "child5";
}
// 和组合继承的区别
Child5.prototype = Object.create(Parent5.prototype);
Child5.prototype.constructor = Child5;

console.log(new Child5());

优点

  • 父类构造函数不会执行两次
  • 父类非原型属性和方法隔离

缺点

  • 需要手动修改 constructor 指向
  • 多个子实例的原型都是指向同一个对象,如果子实例修改了父类原型上的属性,会造成污染,但如果修改的是父类非原型上的属性和方法则不会,因为已经复制了一遍到子实例上

混入寄生组合式继承

  • 继承多个父类
function Child () {
    Parent.call(this)
    OtherParent.call(this)
}
Child.prototype = Object.create(Parent.prototype)
Object.assign(Child.prototype, OtherParent.prototype)
Child.prototype.constructor = Child

function Parent (sex) {
  this.sex = sex
}
Parent.prototype.getSex = function () {
  console.log(this.sex)
}
function OtherParent (colors) {
  this.colors = colors
}
OtherParent.prototype.getColors = function () {
  console.log(this.colors)
}
function Child (sex, colors) {
  Parent.call(this, sex)
  OtherParent.call(this, colors) // 新增的父类
  this.name = 'child'
}
Child.prototype = Object.create(Parent.prototype)
Object.assign(Child.prototype, OtherParent.prototype) // 新增的父类原型对象,只是将 OtherParent.prototype 赋值到了 Parent.prototype 上
Child.prototype.constructor = Child

var child1 = new Child('boy', ['white'])
// child1.getSex()
// child1.getColors()
// console.log(child1)

console.log(Child.prototype.__proto__ === Parent.prototype) // true,因为 Object.assign 是浅拷贝
console.log(Child.prototype.__proto__ === OtherParent.prototype)// false
console.log(child1 instanceof Parent)  // true
console.log(child1 instanceof OtherParent) // false

  • 优缺点和寄生组合继承一致

原型式继承(对象继承)

function create (obj) {
    var newObj = {}
    newObj.__proto__ = obj
    return newObj;
}

优点

  • 在不用构造函数和 new 的方式下实现继承

缺点

  • 继承对象污染问题

寄生式继承(对象继承)

var cat = {
  heart: '❤️',
  colors: ['white', 'black']
}
function createAnother (original) {
    var clone = Object.create(original);
    clone.actingCute = function () {
      console.log('我是一只会卖萌的猫咪')
    }
    return clone;
}
var guaiguai = createAnother(cat)
  • 优缺点和原型式继承一致
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值