JS继承详解

JS继承主要有以下几种:

1.原型链继承:将父类的实例作为子类的原型

function Parent() {
   this.isShow = true
   this.info = {
      name: "yhd",
      age: 18,
   };
}

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

function Child() {};
// 最关键的一行
Child.prototype = new Parent();

2.构造函数继承:通过在子类构造函数中调用父类构造函数,可以在子类构造函数中使用call()apply()方法。

function Parent() {
  this.info = {
    name: "yhd",
    age: 19,
  }
}

function Child() {
// 通过 call 方法将 child构造函数调用时产生的实例对象作为parent的函数上下文
,因此继承了parent的引用属性info。
    Parent.call(this)
}

let child1 = new Child();
child1.info.gender = "男";
console.log(child1.info); // {name: "yhd", age: 19, gender: "男"};

let child2 = new Child();
console.log(child2.info); // {name: "yhd", age: 19}

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

优点:对比原型链继承,构造函数继承的一个优点是子类构造函数可以向父类构造函数传参;父类的的引用属性不会被共享

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

function Parent(name) {
    this.info = { name: name };
}
function Child(name) {
    //继承自Parent,并传参
    Parent.call(this, name);
    
     //实例属性
    this.age = 18
}

let child1 = new Child("yhd");
console.log(child1.info.name); // "yhd"
console.log(child1.age); // 18

上面实例中得知,父类构造函数Parent接受到一个参数name,并将它赋值给属性name,在Child构造函数中调用 Parent构造函数时传入这个参数,实际上会在Child实例上定义name属性。

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,让两个实例都有自己的属性,而且还共享了父类的sayName方法。

总结:组合类继承的优点有三个,父类的方法可以共用、父类构造函数的引用属性不会共享、子类构造函数可以传参。

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"]

缺点:父类的引用属性会被共享(例子中的friends)、子类不能向父类传参。

5.寄生式继承

使用原型式继承实现对目标对象的浅复制,同时增强浅复制的能力

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); // ["rose", "tom", "jack", "lily"]
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对象

  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 = new 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. 只调用一次构造函数

  • 3
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JavaScript 中,继承是一个非常常见的概念。ES6 引入了 Class 语法糖,让继承更加易于理解和实现。在 Class 中,我们可以使用 extends 关键字来创建一个子类,使其继承父类的属性和方法。 下面我们来详细了解一下如何在 JavaScript 中使用 extends 实现继承。 ### 基础语法 首先,我们需要定义一个父类。在 ES6 中,我们可以使用 Class 来定义一个类。例如: ```javascript class Animal { constructor(name) { this.name = name; } speak() { console.log(this.name + ' makes a noise.'); } } ``` 这个 Animal 类有一个构造函数和一个 speak 方法。构造函数会在创建实例时被调用,而 speak 方法则可以让动物发出一些声音。 接下来,我们来创建一个子类。使用 extends 关键字来创建子类,并使用 super() 方法调用父类的构造函数。例如: ```javascript class Dog extends Animal { constructor(name) { super(name); } speak() { console.log(this.name + ' barks.'); } } ``` 这个 Dog 类继承了 Animal 类,并覆盖了其 speak 方法。在构造函数中,我们通过 super() 方法来调用父类的构造函数,并将传递的参数传递给它。 现在,我们可以创建一个 Dog 的实例,并调用其 speak 方法: ```javascript let d = new Dog('Mitzie'); d.speak(); // Mitzie barks. ``` ### 继承父类的方法 当一个子类继承了一个父类时,它会继承父类的属性和方法。例如,在上面的例子中,Dog 类继承了 Animal 类,因此它继承了 Animal 类的 speak 方法。 当我们调用子类的方法时,如果子类没有实现该方法,它会自动调用父类的方法。例如,在上面的例子中,如果我们不覆盖 Dog 类的 speak 方法,它将调用 Animal 类的 speak 方法。 ### 覆盖父类的方法 如果一个子类需要覆盖父类的方法,我们可以在子类中重新定义该方法。例如,在 Dog 类中,我们覆盖了 Animal 类的 speak 方法,使其输出“barks”而不是“makes a noise”。 ### 调用父类的方法 有时候,我们需要在子类中调用父类的方法。我们可以使用 super 关键字来调用父类的方法。例如,在 Dog 类中,我们可以通过调用 super.speak() 来调用 Animal 类的 speak 方法。 ### 总结 继承是一个非常常见的概念,也是面向对象编程中的重要概念之一。在 JavaScript 中,我们可以使用 extends 关键字来实现继承。通过继承,子类可以继承父类的属性和方法,也可以覆盖父类的方法,并且可以调用父类的方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值