javascript中的继承

javascript中的继承

  • 继承分为两类:接口继承(interface)和实现继承(implement).
  • 由于ECMAScript函数没有签名,无法实现接口继承,ECMAScript只支持实现继承,而实现继承主要是依靠原型链来实现的

原型链继承

  • 缺点

    1. 引用值共享问题
      引用值会被所有的实例(这里以两个为例,下面也将都是)共享,一个对象修改了原型属性,那么另一个的原型属性也会被修改

    2. 不能传参
      在创建Child的实例时,不能向Parent传递参数;如果传递也不会有作用


/*
  原型链继承:本质就是改写子类中的proptotype的指向,使其指向父类,这样就能继承父类的属性和方法
*/

// 手机案例
function Phone(band, color) {
  this.band = band;
  this.color = color;
}
Phone.prototype.telephone = function () {
  console.log(`品牌:${this.band},颜色:${this.color},能打电话`);
}
function NewPhone(band, color) {
  this.band = band;
  this.color = color;
}
NewPhone.prototype = new Phone();
NewPhone.prototype.playGame = function () {
  console.log(`品牌:${this.band},颜色:${this.color},能玩游戏`);
}

var oldPhone = new Phone("老式手机", "黑色");
oldPhone.telephone(); // 品牌:老式手机,颜色:黑色,能打电话

var newPhone = new NewPhone("新型手机", "花色");
newPhone.telephone();// 品牌:新型手机,颜色:花色,能打电话
newPhone.playGame();// 品牌:新型手机,颜色:花色,能玩游戏

借用构造函数继承(经典继承)

在子类构造函数中调用父类构造函数,利用用call方法在将来创建的子类实例中调用父类的构造函数

  • 优点:
    1.解决了引用值共享的问题
    2.可以通过Child向Parent传参
  • 缺点:
    1.多执行了一次函数 call
    2.Parent上的原型不能被继承
function Father(name) {
  this.name = name;
  this.obj = {
    name: "AAA"
  }
}
function Son(name, age) {
  Father.call(this, name)
  this.age = age;
}
var p1 = new Son("孙悟空", 30);
p1.obj.name = "BBB"
console.log(p1.name, p1.age, p1.obj);// 孙悟空 30 {name: "BBB"}

var p2 = new Son("杜克",20)
console.log(p2.name, p2.age, p2.obj);// 杜克 20 {name: "AAA"}

组合继承

集原型链和借用构造函数之长

  • 缺点:函数多执行了一次call,调用了两次父类的构造函数,第一次是在子类的原型指向父类的实例时,第二次是执行call时
function Animal(name, color) {
  this.name = name;
  this.color = ["黑色", "白色"]
}
Animal.prototype.showAttribute = function () {
  console.log(`动物的名字:${this.name} 颜色:${this.color}`);
}
function Dog(name, age) {
  Animal.call(this, name);
  this.age = age;
}
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;
Dog.prototype.sayHi = function () {
  console.log(`动物的名字:${this.name} 颜色:${this.color} 年龄:${this.age} 汪汪汪`);
}

var dog = new Dog("大黄", 8);
dog.showAttribute();// 动物的名字:大黄 颜色:黑色,白色
dog.color.push("黄色")
dog.sayHi();// 动物的名字:大黄 颜色:黑色,白色,黄色 年龄:8 汪汪汪

var dog2 = new Dog("小红",7);
dog2.showAttribute();// 动物的名字:大黄 颜色:黑色,白色
dog2.color.push("红色")
dog2.sayHi();// 动物的名字:小红 颜色:黑色,白色,红色 年龄:7 汪汪汪

原型式继承

以一个对象为基础,创建另一个对象,新创建的对象继承了基础对象,并且可以扩充新对象的属性和方法

  • 缺点: 包含引用类型的属性值始终都会共享相应的值,和原型链继承一样。
/* 
  ES5 通过新增 Object.create()方法规范化了原型式继承,此方法可以接受两个参数,
  第一个参数最为新对象原型的对象 和一个为新对象定义额外属性的对象.
*/
function object(o) {
  function F() { }
  F.prototype = o;
  return new F();
}

var person = {
  name: "人类",
  attribute:["走路","跑步","睡觉"],
  run: function () {
    console.log(`我是${this.name},我能${this.attribute}`);
  }
}
var birdMan = object(person);
birdMan.name = "鸟人"
birdMan.attribute.push("飞行");
birdMan.run();// 我是鸟人,我能走路,跑步,睡觉,飞行

var per = object(person);
per.run();// 我是人类,我能走路,跑步,睡觉,飞行

寄生式继承

  • 优点:没有创建自定义类型,因为只是套了个壳子返回对象(这个),这个函数顺理成章就成了创建的新对象。
  • 缺点:
    1.引用类型的值还是会共享,和原型链继承一样
    2.没用到原型,无法复用。
var person = {
  name: "人类",
  attribute:["走路","跑步","睡觉"],
  run: function () {
    console.log(`我是${this.name},我能${this.attribute}`);
  }
}

function creatAnother(origin){
  var clone = Object.create(origin);
  clone.sayHi = function(){
    console.log("I'am clone");
  }
  return clone;
}


var per1 = creatAnother(person);
per1.run();// 我是人类,我能走路,跑步,睡觉
per1.sayHi();// I'am clone
per1.attribute.push("游泳")
var per2 = creatAnother(person);
per2.run(); // 我是人类,我能走路,跑步,睡觉,游泳

寄生组合式继承

最完美的继承,只调用了一次父类的构造函数

 
  function inheritPrototype(son, father) {
    var clonePrototype = Object.create(father.prototype);// 复制父类的原型
    clonePrototype.constructor = son;// 父类的原型指向子类构造函数
    son.prototype = clonePrototype;// 子类原型指向父类原型,原型对原型
  }

  function Animal(name, color) {
    this.name = name;
    this.color = ["黑色", "白色"]
  }
  Animal.prototype.showAttribute = function () {
    console.log(`动物的名字:${this.name} 颜色:${this.color}`);
  }

  function Dog(name, age) {
    Animal.call(this, name);
    this.age = age;
  }
  inheritPrototype(Dog, Animal);
  Dog.prototype.sayHi = function () {
    console.log(`动物的名字:${this.name} 颜色:${this.color} 年龄:${this.age} 汪汪汪`);
  }
  var dog = new Dog("大黄", 8);
  dog.color.push("黄色");
  dog.showAttribute();// 动物的名字:大黄 颜色:黑色,白色,黄色
  dog.sayHi();// 动物的名字:大黄 颜色:黑色,白色,黄色 年龄:8 汪汪汪

  var dog2 = new Dog("小红", 9);
  dog2.color.push("红色")
  dog2.showAttribute();// 动物的名字:小红 颜色:黑色,白色,红色
  dog2.sayHi();// 动物的名字:小红 颜色:黑色,白色,红色 年龄:9 汪汪汪
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值