美文网首页
js继承的几种方式

js继承的几种方式

作者: 0月 | 来源:发表于2019-01-12 20:33 被阅读0次

在我近三年的职业生涯中,老实说,我很少需要自己去写一个类,然后继承,然后如何如何去调用这些方法,除了有一次公司紧急任务需要用canvas写一个打飞机的游戏之外,大多数时间都是用现有的工具,库,框架就能完成任务了。但是呢,写久了就会厌倦,而想要进阶高级前端,面向对象编程,彻底理解原型、闭包这些都是必须的。所以,砥砺前行吧。今天就来聊一聊js继承的几种方式。

一,原型链继承

function Fu(){
  this.name = 'Fu'
  this.sayName = function(){
    console.log(this.name)
  }
}

function Zi(name) {
  this.name = name
}
Zi.prototype = new Fu()

例子1的父类有默认的name='Fu',和一个sayName()方法,子类需要每个实例都有自己的name,如下图,每个实例都有自己的name,并且可以调用父类继承的sayName()方法


例子1.png

虽然上面的方法实现了继承,但是也有问题的。
问题一:切断了 Zi.prototype.constructor与Zi的关系

image.png

Fu.prototype.constructor === Fu // true
这个没问题,
但是
Zi.prototype.constructor === Zi // false
这就不对了,按理来说 Zi.prototype.constructor === Zi //true才是对的,为什么会这样呢?成也萧何败也萧何,问题出在了 Zi.prototype = new Fu()这一句虽然实现了继承,但是也切断了 Zi.prototype.constructor与Zi的关系。相当于给 Zi.prototype重新赋值了,所以要正确无误的继承,在最后我们还要加上这句代码:

 Zi.prototype.constructor = Zi // 重新把他们的关系建立起来。

第二个问题:原型链上的引用类型的数据会被所有实例共享
看下面例子:
1、 Fu中定义了一个引用类型的变量,
2、 Zi类实例z1 z2都能访问到,结果都是['1', '2', '3']
3、z1修改了这个引用类型的变量,z2没修改
4、结果是z2也被影响到了
所以,实际开发一般不会单独用原型链来做。

image.png

二,借用构造函数继承

function Fu(name){
  this.name = name
  this.sayName = function(){
    console.log(this.name)
  }
}
Fu.prototype.sayHi = function (){
  console.log('hi')
}

function Zi() {
  Fu.apply(this, arguments)
}

let z = new Zi('儿子')
console.log(z)

利用apply函数将父类的构造函数直接在子类中运行,这样就等于是把父类的语句搬到子类中,并且把this转移到子类了。如下图例子1, 实例z 继承了父类的sayName()方法,但是也有缺点:
1、Fu.prototype上的方法无法继承
2、Fu构造函数中定义的方法无法复用

例子2.png

三、组合继承

说白就是把前面两种组合起来

function Fu(){
  this.name = 'Fu'
}

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

function Zi(name) {
  Fu.apply(this, arguments)
  this.name = name
}
Zi.prototype = new Fu()
Zi.prototype.constructor = Zi
let z = new Zi('儿子')

优点:解决上面的问题
缺点:调用两次Fu的构造函数

四、寄生组合式继承

function Fu(){
  this.name = 'Fu'
}

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

function Zi(name) {
  Fu.apply(this, arguments)
  this.name = name
}
Zi.prototype = Obeject.create(Fu.prototype)
Zi.prototype.constructor = Zi
let z = new Zi('儿子')

基本到这里就没啥问题了,Obeject.create(Fu.prototype)这句就是对Fu.prototype的浅拷贝,而不是调用Fu的构造函数。

// Obeject.create(Fu.prototype)相当于下面的函数
function create(obj) {
  let F = function(){}
  F.prototype = obj
  return new F()
}
create(Fu.prototype)

五、class extends

class和extends是在ES6中新增的,class用来创建一个类,extends用来实现继承

class Fu{
  constructor(name){
    this.name = name
  }
  sayName(){
    console.log(this.name)
  } 
}

class Zi extends Fu{
  constructor(name){
    super(name) // 这句很重要
    this.name = name
  }
}

注意:子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象。

相关文章

  • js几种继承方式

    注意: 1,constructor总是指向类的构造函数 2,__proto__指向父类的原型对象 1,原型链继承 ...

  • JavaScript 继承

    继承是JS中非常内容,原因就是JS没有地道的继承方式,我们只能通过各种方式来模拟面向对象中的继承。下面介绍几种常见...

  • JS继承的几种方式

    关于Js继承的几种方式,总结一下,以便查看。 第一种 prototype 引用型原型继承 语言支持:js原生支持的...

  • JS继承的几种方式

    JS继承的几种方式 (1) 属性拷贝 存在问题: 如果继承过来的成员是引用类型的话,那么这个引用类型的成员在父对象...

  • js继承的几种方式

    1 原型链继承 把子类的prototype指向父级的实例,也就是原型链继承 此继承方法优 简单明了,父级新增的属性...

  • js继承的几种方式

    在我近三年的职业生涯中,老实说,我很少需要自己去写一个类,然后继承,然后如何如何去调用这些方法,除了有一次公司紧急...

  • 聊一聊js的几种继承方式

    在js中, 很多地方需要使用到继承, 废话少说, 今天来聊一聊js几种继承方式的优缺点 构造函数继承functio...

  • JavaScript常见的继承方式

    前言 JS作为面向对象的弱类型语言,继承也是其非常强大的特性之一。那么在JS中常见的继承方式有几种呢? 方式一、原...

  • js 的继承的几种方式

    js 继承有6种方式的代码。 js继承的6种方式[https://www.cnblogs.com/Grace-zy...

  • 彻底弄清js继承的几种实现方式

    js有几种经典的继承方式。比如原型链继承、构造函数继承、组合继承、寄生组合继承、ES6继承。让我们一一分析并实现。...

网友评论

      本文标题:js继承的几种方式

      本文链接:https://www.haomeiwen.com/subject/yijcdqtx.html