JavaScript之面向对象继承

JavaScript虽然是面向对象的程序设计语言,但与其他面向对象的语言有很大的不同,JavaScript没有真正的类,是基于原型的面向对象语言,用函数作为类的构造函数,通过复制构造函数的方式来模拟继承。

ES6加入了class关键字来处理对象,但依旧是基于原型来实现的。JavaScript类的语法更像是一种语法糖。

继承的不同实现方式

继承是面向对象语言的核心特性之一,JavaScript使用原型实现继承。

继承最佳效果就是在不影响父类对象的实现下,使子类对象具有父类对象的特征,同时可以在不影响父类对象行为的情况下,扩展子类对象独有的特性。

如果希望对象的属性具有默认值,同时在运行时能修改这些默认值,可以在对象的原型中设置这些属性,而不是在构造函数中设置。一般情况下,静态属性写在构造函数中,动态属性和方法写在构造函数原型上。

原型链继承

实现方法:将父类的实例作为子类的原型

function Employee() {
  this.name = '苏白'
}

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

function Manager() {
  this.reports = []
}

Manager.prototype = new Employee() // 核心

const clh = new Manager()
clh.sayName() // 苏白

当JavaScript执行new Manager()式,会先创造clh对象,并将这个对象中的[[prototype]]指向Manager.prototype,然后将该对象作为this的值传递给Manager()构造函数。

使用原型链继承创建子类时,不能向父类构造函数中传递参数

借用构造函数继承

实现:call()或者apply()复制父类的实例属性和方法给子类

function Employee() {
  this.name = '苏白'
}

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

function Manager() {
  Employee.call(this) // 核心
  this.reports = []
}

const clh = new Manager()

console.log(clh.name) // 苏白

// clh.sayName() //  Uncaught TypeError: clh.sayName is not a function

借用构造函数继承完全没有用到原型,但可以向父类构造函数中传递参数

原型式继承

JavaScript中,空对象是整个原型继承体系的基础。

已有一个对象,在其基础上创建新对象,然后对返回的新对象进行适当修改,这样即使不定义构造函数也可以通过原型实现对象之间的信息共享

function object(o) {
  function F() {}

  F.prototype = o
  return new F()
}

const person = {
  name: '苏白',
  friends: ['崔洛恒']
}
const person1 = object(person)

person1.name = '邱文'
person1.friends.push('叶深')
console.log(person1.friends)
console.log(Object.getPrototypeOf(person1))

原型式继承的实现基于原型链,可以使用instanceof判断对象是否为某个类或其子类的实例

类式继承

使用Object.create()可以实现类式继承,现有的对象提供新创建的对象原型。

这种继承方式是一种单继承,JavaScript的不同版本都支持。

// 父类
function Shape() {
  this.x = 0
  this.y = 0
}

// 父类的方法
Shape.prototype.move = function (x, y) {
  this.x += x
  this.y += y
  console.log('Shape moved')
}

// 子类
function Rectangle() {
  // 借用构造函数
  Shape.call(this)
}

// 子类继承父类
Rectangle.prototype = Object.create(Shape.prototype)
// 重新指定构造函数
Rectangle.prototype.constructor = Rectangle

const rect = new Rectangle()
console.log(rect instanceof Rectangle) // true
console.log(rect instanceof Shape) // true

想要继承多个对象,可以使用Object.assign()

寄生式组合继承

通过借用构造函数来继承属性,通过原型链形式继承方法。

本质:使用寄生式继承来继承超类型的原型,然后将结构指定给子类型的原型

寄生式继承主要创建一个封装基础过程的函数,在函数内部以某种方式来增强对象,最后返回对象

 // 寄生式组合继承实现函数
function inheritPrototype(subType, superType) {
  // 创建父类原型副本
  let prototype = Object.create(superType.prototype)
  // 修正子类原型构造函数
  prototype.constructor = subType
  // 将子类的原型替换成父类原型副本
  subType.prototype = prototype
}

// 父类构造函数
function SuperType(name) {
  this.name = name
  this.colors = ['red', 'green', 'blue']
}

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

// 子类构造函数
function SubType(name, age) {
  // 构造函数式继承——在子类构造函数中执行父类构造函数
  SuperType.call(this, name)
  this.age = age
}

//  对父类原型复制,不会两次调用父类的构造函数
inheritPrototype(SubType, SuperType)
SubType.prototype.sayAge = function () {
  console.log(this.age)
}

const instance = new SubType('javascript', new Date().getFullYear() - 1995)
console.log(`${instance.name}已经${instance.age}岁了`)
// 指向SubType 若没有修正原型的构造函数,会指向父类构造函数
console.log(instance.constructor) 

寄生式组合继承是实现继承比较理想的一种方式

类的继承

JavaScript中使用关键字class定义类,使用extends关键字可以继承任何拥有[[constructor]]和原型的对象。

也就是说,extends不仅可以用来继承类,也可以继承普通的构造函数。

语法格式:

class ChildClass extends ParentClass {}

父类可以是普通类、内置对象,也可以扩展null,但是新对象的原型不会继承Object.prototype()。

子类可以通过super关键字引用它们的原型(super只能在子类中使用,并且仅限于构造函数、原型方法和静态方法内部。)

在super()之前不能引用this,否则实例化时会报错。子类并没有自己的this对象,需要继承父类的this对象获取。

class Animal {
  constructor(name) {
    this.name = name
  }

  running() {
    console.log(`${this.name}跑了`)
  }
}

class Dog extends Animal {
  constructor(name, age) {
    super(name)
    this.age = age
  }
  eating(){
    console.log(`${this.name}今年${this.age}岁,能啃大骨头`)
  }
}

const dog = new Dog('小白',1)
dog.running() 
dog.eating() 
  • 25
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值