js--继承

1. 原型链继承

将父类的实例作为子类的原型

function Parent(){
    this.isShow=ture;
    this.info={
        name:"hh",
        age:14,
    }
}

Parent.prototype.getInfo=function(){
    console.log(this.isShow);
    console.log(this.info);
 }

function Child(){};
Child.prototype=new Parent();


let child_1 = new Child();
child_1.getInfo(); //{name:"hh",age:14,gender:"nan"}

let child_2 = new Child();
child_2.info.gender="nan";
child_2.getInfo(); //{name:"hh",age:14,gender:"nan"}
child_2.isShow=false;

console.log(child_2.isShow); //false

 优点

父类方法可以复用

缺点 

1. 父类的所有引用属性(info)会被所有子类共享,更改一个子类的引用属性,其他子类的引用属性也会改变;

2. 子类实例不能给父类构造函数传参。

2. 盗用构造函数继承(构造函数继承) 

 在子类构造函数中调用父类构造函数,可以在子类构造函数中使用call()apply()等方法。

function Parent(){
    this.info={
        name:"ff",
        age:39,
    }
}

function Child(){
   Parent.call(this);
}

let child_1 = new Child();
child_1.info.gender="nan";
console.log(child_1.info); //{name:"ff",age:39,gender:"nan"}

let child_2 = new Child();
console.log(child_2.info);//{name:"ff",age:39}

 通过使用 call() 或 apply() 方法,Parent构造函数在为Child的实例创建的新对象的上下执行了,就相当于新的child实例对象上运行了Parent()函数中的所有初始化代码,结果就是每个实例都有自己的info属性。

1. 传递参数

相比于原型链继承,构造函数继承的一大特点就是子类构造函数可以向父类构造函数传递参数。

funciton Parent(name){
    this.info={
        name:name
    }
}

function Child(name){
    Parent.call(this,name};
    this.age=29;
}

let child_1 = new Child("kk");
child_1.age=90;
console.log(child_1.info); //{name:"kk"}
console.log(child_1.age); //90


let child_2 = new Child("ff");
console.log(child_2.info); //{name:"ff"}
console.log(child_2.age); //29

在上面的例子中,Parent构造函数接收一个name参数,并将他赋值给一个属性,在Child构造函数中调用Parent构造函数时传入这个参数,实际上会在Child实例上定义name属性。为确保Parent构造函数不会覆盖Child定义的属性,可以自调用父类构造函数只后再给子类实例添加额外的属性。

优点

1.可以在子类构造函数中向父类传递参数

2. 父类的引用属性不会被共享。 

 缺点

1. 子类不能访问父类原型上定义的方法(即不能访问Parent.prototype上定义的方法)。因此所有方法属性都写在构造函数中。每次创建实例都会初始化。

 3. 组合继承

组合继承综合了原型链继承和构造函数继承,综合了两种的优点。

基本思路就是使用原型链继承原型上的属性和方法,通过构造函数继承实例上的属性。这样既可以把方法定义在原型上以实现复用,又可以让每个实例有自己的属性。 

function Parent(name) {
   this.name = name
   this.colors = ["red", "blue", "yellow"]
}
Parent.prototype.sayName = function () {
   console.log(this.name);
}

function Child(name, age) {
   // 继承父类属性
   Parent.call(this, name)
   this.age = age;
}
// 继承父类方法
Child.prototype = new Parent();

Child.prototype.sayAge = function () {
   console.log(this.age);
}

let child1 = new Child("yhd", 19);
child1.colors.push("pink");
console.log(child1.colors); // ["red", "blue", "yellow", "pink"]
child1.sayAge(); // 19
child1.sayName(); // "yhd"

let child2 = new Child("wxb", 30);
console.log(child2.colors);  // ["red", "blue", "yellow"]
child2.sayAge(); // 30
child2.sayName(); // "wxb"

​ 上面例子中,Parent构造函数定义了name,colors两个属性,接着又在他的原型上添加了个sayName()方法。Child构造函数内部调用了Parent构造函数,同时传入了name参数,同时Child.prototype也被赋值为Parent实例,然后又在他的原型上添加了个sayAge()方法。这样就可以创建 child1,child2两个实例,让这两个实例都有自己的属性,包括colors,同时还共享了父类的sayName方法。

优点

1. 父类方法可以复用;

2. 子类构造函数可以向父类构造函数传递参数;

3. 父类构造函数的属性不会共享。

4. 原型式继承

对参数对象的一种浅复制 

function objectCopy(obj) {
  function Fun() { };
  Fun.prototype = obj;
  return new Fun()
}

let person = {
  name: "yhd",
  age: 18,
  friends: ["jack", "tom", "rose"],
  sayName:function() {
    console.log(this.name);
  }
}

let person1 = objectCopy(person);
person1.name = "wxb";
person1.friends.push("lily");
person1.sayName(); // wxb

let person2 = objectCopy(person);
person2.name = "gsr";
person2.friends.push("kobe");
person2.sayName(); // "gsr"

console.log(person.friends); // ["jack", "tom", "rose", "lily", "kobe"]

 优点:

父类方法可复用

缺点:

1. 父类的引用会被所有子类共享;

2. 子列实例不能向父类传参

ES5的Object.create() 方法只有第一个参数时,与这里的objectCopy()方法效果相同。

5. 寄生式继承

 使用原型式继承对一个目标对象进行浅复制,增强这个浅复制的能力。6.

function objectCopy(obj) {
  function Fun() { };
  Fun.prototype = obj;
  return new Fun();
}

function createAnother(original) {
  let clone = objectCopy(original);
  clone.getName = function () {
    console.log(this.name);
  };
  return clone;
}

let person = {
     name: "yhd",
     friends: ["rose", "tom", "jack"]
}

let person1 = createAnother(person);
person1.friends.push("lily");
console.log(person1.friends);
person1.getName(); // yhd

let person2 = createAnother(person);
console.log(person2.friends); // ["rose", "tom", "jack", "lily"]

6. 寄生式组合继承 

function objectCopy(obj) {
  function Fun() { };
  Fun.prototype = obj;
  return new Fun();
}

function inheritPrototype(child, parent) {
  let prototype = objectCopy(parent.prototype); // 创建对象
  prototype.constructor = child; // 增强对象
  Child.prototype = prototype; // 赋值对象
}

function Parent(name) {
  this.name = name;
  this.friends = ["rose", "lily", "tom"]
}

Parent.prototype.sayName = function () {
  console.log(this.name);
}

function Child(name, age) {
  Parent.call(this, name);
  this.age = age;
}

inheritPrototype(Child, Parent);
Child.prototype.sayAge = function () {
  console.log(this.age);
}

let child1 = new Child("yhd", 23);
child1.sayAge(); // 23
child1.sayName(); // yhd
child1.friends.push("jack");
console.log(child1.friends); // ["rose", "lily", "tom", "jack"]

let child2 = new Child("yl", 22)
child2.sayAge(); // 22
child2.sayName(); // yl
console.log(child2.friends); // ["rose", "lily", "tom"]

 优点:

  1. 只调用一次父类构造函数
  2. Child可以向Parent传参
  3. 父类方法可以复用
  4. 父类的引用属性不会被共享

寄生式组合继承可以算是引用类型继承的最佳模式 

转载:掘金https://juejin.cn/post/6914216540468576263#heading-3 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值