欢迎来到代码驿站!

JavaScript代码

当前位置:首页 > 网页前端 > JavaScript代码

Javascript的ES5,ES6的7种继承详解

时间:2023-02-23 09:10:49|栏目:JavaScript代码|点击:

众所周知,在ES6之前,前端是不存在类的语法糖,所以不能像其他语言一样用extends关键字就搞定继承关系,需要一些额外的方法来实现继承。下面就介绍一些常用的方法,红宝书已经概括的十分全面了,所以本文基本就是对红宝书继承篇章的笔记和梳理。

原型链继承

function Parent() {
    this.name = 'arzh'
}
Parent.prototype.getName = function () {
    console.log(this.name)
}
function Child() {
}
//主要精髓所在
Child.prototype = new Parent()
Child.prototype.constructor = Child
var arzhChild = new Child()
arzhChild.getName() // 'arzh'

原型链继承缺点:

1.每个实例对引用类型属性的修改都会被其他的实例共享

function Parent() {
    this.names = ['arzh','arzh1'];
}
function Child() {
}
//主要精髓所在
Child.prototype = new Parent()
Child.prototype.constructor = Child
var arzhChild2 = new Child()
arzhChild2.names.push('arzh2')
console.log(arzhChild2.names) //[ 'arzh', 'arzh1', 'arzh2' ]
var arzhChild3 = new Child()
arzhChild3.names.push('arzh3')
console.log(arzhChild3.names) //[ 'arzh', 'arzh1', 'arzh2', 'arzh3' ]

2.在创建Child实例的时候,无法向Parent传参。这样就会使Child实例没法自定义自己的属性(名字)

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

function Parent() {
    this.names = ['arzh','arzh1']
}
function Child() {
    Parent.call(this)
}
var arzhChild2 = new Child()
arzhChild2.names.push('arzh2')
console.log(arzhChild2.names) //[ 'arzh', 'arzh1', 'arzh2' ]
var arzhChild3 = new Child()
arzhChild3.names.push('arzh3')
console.log(arzhChild3.names) //[ 'arzh', 'arzh1', 'arzh3' ]

优点:

  • 解决了每个实例对引用类型属性的修改都会被其他的实例共享的问题
  • 子类可以向父类传参
function Parent(name) {
    this.name = name
}
function Child(name) {
    Parent.call(this, name)
}
var arzhChild = new Child('arzh');
console.log(arzhChild.name); // arzh
var arzhChild1 = new Child('arzh1');
console.log(arzhChild1.name); // arzh1

缺点:

  • 无法复用父类的公共函数
  • 每次子类构造实例都得执行一次父类函数

组合式继承(原型链继承和借用构造函数合并)

function Parent(name) {
    this.name = name
    this.body = ['foot','hand']
}
function Child(name, age) {
    Parent.call(this, name)
    this.age = age
}
Child.prototype = new Parent()
Child.prototype.constructor = Child
var arzhChild1 = new Child('arzh1', '18')
arzhChild1.body.push('head1')
console.log(arzhChild1.name,arzhChild1.age) //arzh1 18
console.log(arzhChild1.body) //[ 'foot', 'hand', 'head1' ]
var arzhChild2 = new Child('arzh2', '20')
arzhChild2.body.push('head2')
console.log(arzhChild2.name,arzhChild2.age) //arzh2 20
console.log(arzhChild2.body) //[ 'foot', 'hand', 'head2' ]

优点:

  • 解决了每个实例对引用类型属性的修改都会被其他的实例共享的问题
  • 子类可以向父类传参
  • 可实现父类方法复用

缺点:

  • 需执行两次父类构造函数,第一次是Child.prototype = new Parent(),第二次是Parent.call(this, name)造成不必要的浪费

原型式继承

复制传入的对象到创建对象的原型上,从而实现继承

function createObj(o) {
    function F(){}
    F.prototype = o;
    return new F();
}
var person = {
    name : 'arzh',
    body : ['foot','hand']
}
var person1 = createObj(person)
var person2 = createObj(person)
console.log(person1) //arzh
person1.body.push('head') 
console.log(person2) //[ 'foot', 'hand', 'head' ]

缺点: 同原型链继承一样,每个实例对引用类型属性的修改都会被其他的实例共享

寄生式继承

我们可以使用Object.create来代替上述createObj的实现,原理基本上是一样的。寄生式继承其实就是在createObj的内部以某种形式来增强对象(这里的增强可以理解为添加对象的方法),最后返回增强之后的对象。

function createEnhanceObj(o) {
    //代替原型式继承的createObj
    var clone = Object.create(o)
    clone.getName = function () {
        console.log('arzh')
    }
    return clone;
}

通过createEnhanceObj就可以在创建对象的时候,把对象方法也通过此种方式继承。

缺点: 同借用构造函数一样,无法复用父类函数,每次创建对象都会创建一遍方法

寄生组合式继承

不需要为了子类的原型而多new了一次父类的构造函数,如Child.prototype = new Parent() 只需要复制父类原型的一个副本给子类原型即可

function inheritPrototype(Parent, Child){
	Child.prototype = Object.create(Parent.prototype) //创建父类原型的一个副本,把副本赋值给子类原型
	Child.prototype.constructor = Child;
}
function Parent(name) {
    this.name = name
}
Parent.prototype.getName = function () {
    console.log(this.name)
}
function Child(color) {
    Parent.call(this, 'arzh')
    this.color = color
}
inheritPrototype(Parent, Child)
var arzhChild = new Child('red')
console.log(arzhChild.name) // 'arzh'

优点: 不必为了指定子类型的原型而调用父类型的构造函数

ES6继承

ES6支持通过类来实现继承,方法比较简单,代码如下

class Point {
    constructor(x, y) {
        this.x = x
        this.y = y
    }
    toString() {
        return this.x + '' + this.y
    }
}
class ColorPoint extends Point {
    constructor(x, y, color) {
        super(x, y) //调用父类的constructor(x, y)
        this.color = color
    }
    toString() {
        return this.color + ' ' + super.toString() // 调用父类的toString()
    }
}
var colorPoint = new ColorPoint('1', '2', 'red')
console.log(colorPoint.toString())  // red 12

总结

上一篇:JS实现的JSON序列化操作简单示例

栏    目:JavaScript代码

下一篇:Bootstrap的modal拖动效果

本文标题:Javascript的ES5,ES6的7种继承详解

本文地址:http://www.codeinn.net/misctech/226311.html

推荐教程

广告投放 | 联系我们 | 版权申明

重要申明:本站所有的文章、图片、评论等,均由网友发表或上传并维护或收集自网络,属个人行为,与本站立场无关。

如果侵犯了您的权利,请与我们联系,我们将在24小时内进行处理、任何非本站因素导致的法律后果,本站均不负任何责任。

联系QQ:914707363 | 邮箱:codeinn#126.com(#换成@)

Copyright © 2020 代码驿站 版权所有