JS中常见的8种继承方法总结

 更新时间:2023年10月17日 15:17:19   作者:酥脆角  
这篇文章主要给大家介绍了关于JS中常见的8种继承方法,在js中所有的引用类型都继承了Object,而继承也是通过原型链实现的,文中通过代码介绍的非常详细,需要的朋友可以参考下

1. 原型链继承:

原型链继承是JavaScript中最基本的继承方式。每个对象都有一个原型对象,通过原型链将属性和方法沿着对象链传递下来。在原型链继承中,通过将子构造函数的原型对象指向父构造函数的实例,实现了继承。这意味着子对象可以访问父对象原型链上的属性和方法。

function Parent() {
  this.name = 'Parent';
}
Parent.prototype.sayHello = function() {
  console.log('Hello');
};

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

var child = new Child();
child.sayHello(); // Hello
function Parent() {
  this.name = 'Parent';
}
Parent.prototype.sayHello = function() {
  console.log('Hello');
};

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

var child = new Child();
child.sayHello(); // Hello

在这个例子中,Child对象的原型对象被设置为Parent的一个实例。这样,当我们调用child.sayHello()时,它会首先在子对象上查找sayHello方法,然后在父对象原型链上找到并执行该方法。注意:原型链继承的缺点是,所有子对象共享同一个原型对象,对原型对象的修改会影响到所有子对象。

2. 构造函数继承(经典继承):

构造函数继承是通过在子构造函数中调用父构造函数来实现继承。在构造函数继承中,通过在子构造函数中使用**call()apply()**方法,将父构造函数的上下文设置为子对象的上下文,从而实现继承。

function Parent(name) {
  this.name = name;
}

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

var child = new Child('Child');
console.log(child.name); // Child
function Parent(name) {
  this.name = name;
}

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

var child = new Child('Child');
console.log(child.name); // Child

在这个例子中,我们通过在Child构造函数内部调用Parent构造函数,并传递子对象特定的参数,实现了继承。注意:构造函数继承只能继承父构造函数的实例属性,无法继承父构造函数的原型对象上的方法。

3. 组合继承:

组合继承结合了原型链继承和构造函数继承,既继承了父构造函数的属性,又继承了父构造函数原型对象上的方法。在组合继承中,通过调用父构造函数的方式实现属性的继承,通过将子构造函数的原型对象指向父构造函数的实例实现方法的继承。

function Parent(name) {
  this.name = name;
}
Parent.prototype.sayHello = function() {
  console.log('Hello');
};

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

var child = new Child('Child');
child.sayHello(); // Hello
function Parent(name) {
  this.name = name;
}
Parent.prototype.sayHello = function() {
  console.log('Hello');
};

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

var child = new Child('Child');
child.sayHello(); // Hello

在这个例子中,我们通过调用**Parent.call(this, name)来继承父构造函数的属性,并通过Child.prototype = new Parent()**将子构造函数的原型对象指向父构造函数的实例,从而实现方法的继承。组合继承的优点是既能够继承父构造函数的属性,又能够继承父构造函数原型对象上的方法。然而,缺点是在创建子对象时会调用两次父构造函数,一次是在设置原型时,一次是在创建子对象时。这样会产生一些不必要的开销。

4. 原型式继承:

原型式继承是通过使用一个临时构造函数和**Object.create()**方法来实现继承。

var parent = {
  name: 'Parent',
  sayHello: function() {
    console.log('Hello');
  }
};

var child = Object.create(parent);
console.log(child.name); // Parent
child.sayHello(); // Hello
var parent = {
  name: 'Parent',
  sayHello: function() {
    console.log('Hello');
  }
};

var child = Object.create(parent);
console.log(child.name); // Parent
child.sayHello(); // Hello

在这个例子中,我们创建了一个parent对象,然后使用**Object.create()**方法创建了一个新对象child,并将其原型对象指向parent对象,实现了继承。原型式继承的本质是创建一个新对象,将其原型对象指向另一个已有的对象。这种方式可以实现属性和方法的继承,但是不能传递构造函数的参数。

5. Object.create()

Object.create() 是把现有对象的属性,挂到新建对象的原型上,新建对象为空对象

ECMAScript 5通过增加Object.create()方法将原型式继承的概念规范化了。这个方法接收两个参数:作为新对象原型的对象,以及给新对象定义额外属性的对象(第二个可选)。在只有一个参数时,Object.create()与这里的函数A方法效果相同。

let person = {
  name: 'mjy',
  age: 19,
  hoby: ['唱', '跳'],
  showName() {
    console.log('my name is: ', this.name)
  }
}
 
let child1 = Object.create(person)
child1.name = 'xxt'
child1.hoby.push('rap')
let child2 = Object.create(person)
 
console.log(child1)
console.log(child2)
console.log(person.hoby) // ['唱', '跳', 'rap']let person = {
  name: 'mjy',
  age: 19,
  hoby: ['唱', '跳'],
  showName() {
    console.log('my name is: ', this.name)
  }
}
 
let child1 = Object.create(person)
child1.name = 'xxt'
child1.hoby.push('rap')
let child2 = Object.create(person)
 
console.log(child1)
console.log(child2)
console.log(person.hoby) // ['唱', '跳', 'rap']

优点: 不需要单独创建构造函数。

缺点: 属性中包含的引用值始终会在相关对象间共享,子类实例不能向父类传参

6. 寄生式继承

寄生式继承的思路与(寄生) 原型式继承 和 工厂模式 似, 即创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真的是它做了所有工作一样返回对象。

function objectCopy(obj) {
  function Fun() { };
  Fun.prototype = obj;
  return new Fun();
}
 
function createAnother(obj) {
  let clone = objectCopy(obj);
  clone.showName = function () {
    console.log('my name is:', this.name);
  };
  return clone;
}
 
let person = {
     name: "mjy",
     age: 18,
     hoby: ['唱', '跳']
}
 
let child1 = createAnother(person);
child1.hoby.push("rap");
console.log(child1.hoby); // ['唱', '跳', 'rap']
child1.showName(); // my name is: mjy
 
let child2 = createAnother(person);
console.log(child2.hoby); // ['唱', '跳', 'rap']function objectCopy(obj) {
  function Fun() { };
  Fun.prototype = obj;
  return new Fun();
}
 
function createAnother(obj) {
  let clone = objectCopy(obj);
  clone.showName = function () {
    console.log('my name is:', this.name);
  };
  return clone;
}
 
let person = {
     name: "mjy",
     age: 18,
     hoby: ['唱', '跳']
}
 
let child1 = createAnother(person);
child1.hoby.push("rap");
console.log(child1.hoby); // ['唱', '跳', 'rap']
child1.showName(); // my name is: mjy
 
let child2 = createAnother(person);
console.log(child2.hoby); // ['唱', '跳', 'rap']

优点: 写法简单,不需要单独创建构造函数。

缺点: 通过寄生式继承给对象添加函数会导致函数难以重用。使用寄生式继承来为对象添加函数, 会由于不能做到函数复用而降低效率;这一点与构造函数模式类似.

7. 寄生组合式继承

前面讲过,组合继承是常用的经典继承模式,不过,组合继承最大的问题就是无论什么情况下,都会调用两次父类构造函数;一次是在创建子类型的时候,一次是在子类型的构造函数内部。寄生组合继承就是为了降低父类构造函数的开销而实现的。

通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。

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.hoby = ['唱', '跳']
}
 
Parent.prototype.showName = function () {
  console.log('my name is:', this.name);
}
 
function Child(name, age) {
  Parent.call(this, name);
  this.age = age;
}
 
inheritPrototype(Child, Parent);
Child.prototype.showAge = function () {
  console.log('my age is:', this.age);
}
 
let child1 = new Child("mjy", 18);
child1.showAge(); // 18
child1.showName(); // mjy
child1.hoby.push("rap");
console.log(child1.hoby); // ['唱', '跳', 'rap']
 
let child2 = new Child("yl", 18);
child2.showAge(); // 18
child2.showName(); // yl
console.log(child2.hoby); // ['唱', '跳']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.hoby = ['唱', '跳']
}
 
Parent.prototype.showName = function () {
  console.log('my name is:', this.name);
}
 
function Child(name, age) {
  Parent.call(this, name);
  this.age = age;
}
 
inheritPrototype(Child, Parent);
Child.prototype.showAge = function () {
  console.log('my age is:', this.age);
}
 
let child1 = new Child("mjy", 18);
child1.showAge(); // 18
child1.showName(); // mjy
child1.hoby.push("rap");
console.log(child1.hoby); // ['唱', '跳', 'rap']
 
let child2 = new Child("yl", 18);
child2.showAge(); // 18
child2.showName(); // yl
console.log(child2.hoby); // ['唱', '跳']

优点: 高效率只调用一次父构造函数,并且因此避免了在子原型上面创建不必要,多余的属性。与此同时,原型链还能保持不变;

缺点: 代码复杂

8. ES6类继承:

在ES6中引入了类的概念,通过class关键字和extends关键字可以实现类的继承。

class Parent {
  constructor(name) {
    this.name = name;
  }

  sayHello() {
    console.log('Hello');
  }
}

class Child extends Parent {
  constructor(name) {
    super(name);
  }
}

const child = new Child('Child');
console.log(child.name); // Child
child.sayHello(); // Hello
class Parent {
  constructor(name) {
    this.name = name;
  }

  sayHello() {
    console.log('Hello');
  }
}

class Child extends Parent {
  constructor(name) {
    super(name);
  }
}

const child = new Child('Child');
console.log(child.name); // Child
child.sayHello(); // Hello

在这个例子中,我们定义了一个Parent类,通过extends关键字实现子类Child对父类Parent的继承。子类使用super关键字调用父类的构造函数,并可以访问父类的属性和方法。ES6类继承提供了更加语法简洁和面向对象的继承方式。

以上是JavaScript中常见的八种继承方式,每种方式都有其特点和适用场景。根据具体需求,你可以选择适合的继承方式来构建对象之间的关系。

总结

到此这篇关于JS中常见的8种继承方法的文章就介绍到这了,更多相关JS继承方法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 基于three.js实现简易照片墙效果

    基于three.js实现简易照片墙效果

    这篇文章主要为大家详细介绍了基于three.js实现简易照片墙效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-04-04
  • 深入解析Javascript闭包的功能及实现方法

    深入解析Javascript闭包的功能及实现方法

    这篇文章主要为大家详细解析Javascript闭包的功能及实现方法,感兴趣的小伙伴们可以参考一下
    2016-07-07
  • IE与Firefox在JavaScript上的7个不同写法小结

    IE与Firefox在JavaScript上的7个不同写法小结

    尽管那需要用长串的、沉闷的不同分支代码来应付不同浏览器的日子已经过去,偶尔还是有必要做一些简单的区分和目标检测来确保某块代码能在用户的机器上正常运行。
    2009-09-09
  • JS 特殊运算符的使用

    JS 特殊运算符的使用

    JavaScript中包含了一系列不常见但功能强大的特殊运算符,如空值合并运算符(??)、可选链运算符(?.)等,这些运算符在特定场景下极大地简化了代码的复杂度,并提高了开发效率,通过深入了解这些特殊运算符,开发者可以更加高效地处理各种数据和逻辑
    2024-09-09
  • 了解Javascript的模块化开发

    了解Javascript的模块化开发

    这篇文章主要介绍了了解Javascript的模块化开发,本文讲解了为什么需要模块化开发,模块化开发的形成原因等内容,需要的朋友可以参考下
    2015-03-03
  • 关于layui toolbar和template的结合使用方法

    关于layui toolbar和template的结合使用方法

    今天小编就为大家分享一篇关于layui toolbar和template的结合使用方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-09-09
  • JS实现网页上随机产生超链接地址的方法

    JS实现网页上随机产生超链接地址的方法

    这篇文章主要介绍了JS实现网页上随机产生超链接地址的方法,涉及JavaScript随机数的相关使用技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-11-11
  • JS实现计算小于非负数n的素数的数量算法示例

    JS实现计算小于非负数n的素数的数量算法示例

    这篇文章主要介绍了JS实现计算小于非负数n的素数的数量算法,可实现针对一定范围内素数个数的统计功能,涉及javascript数值运算相关操作技巧,需要的朋友可以参考下
    2019-02-02
  • 如何使用gpu.js改善JavaScript的性能

    如何使用gpu.js改善JavaScript的性能

    这篇文章主要介绍了如何使用gpu.js改善JavaScript的性能,帮助大家更好的理解和使用JavaScript,感兴趣的朋友可以了解下
    2020-12-12
  • JS利用时间戳倒计时的实现示例

    JS利用时间戳倒计时的实现示例

    这篇文章主要介绍了JS利用时间戳倒计时的实现示例,本文将提供代码示例和详细的步骤,帮助你实现一个简单而实用的时间戳倒计时,感兴趣的可以了解一下
    2023-12-12

最新评论