乐趣区

关于前端:JavaScript内的继承

● 在 JavaScript 内, 继承是面向对象变成中一个重要的开发思维, 外围就是让 A 对象应用 B 对象的属性和办法. 说白了, 就是为了资源整合, 让咱们的代码复用性更高, 前期的可维护性和可扩展性也更高.

● 在 JS 中, 每一个对象都有一个本人的原型对象, JS 内的继承就是依赖这个原型对象, 而且原型对象也有本人的原型对象, 就是这一个一个的原型对象组成了原型链, 这就是继承的外围.

● 举个例子 :

○ 有一位老父亲, 致力了半辈子, 盖了一个大房子

○ 这个时候, 不论这个老父亲有多少个儿子, 他的儿子都是能够住在这个房子外面的

○ 能够用这个房子所有内容

○ 然而如果要是没有继承的话, 那么他的每一个儿子都要本人去从新盖房子

● 这就是咱们继承的意义, 接下来咱们就具体的说一说 JavaScript 内常见的继承计划

回顾之前的知识点
原型
● 构造函数(类) 有一个本人的属性 prototype, 是一个对象

● 每一个对象都有一个本人的属性 __proto__, 指向所属构造函数的 prototype

● 这样, 就将构造函数和对象连接了起来

原型链
● 原型链就是 proto 串联起来的对象链状构造

● 每一个对象都会有本人的原型对象(proto )

原型链拜访规定
● 对象成员的拜访规定就是依照原型链的机制进行拜访的

● 当你拜访一个对象的成员的时候

○ 会首先在对象本人内查找

○ 如果本人有, 间接应用本人的

○ 如果本人没有, 就会主动去到本人的 proto 查找

○ 如果还没有, 在持续去 proto 查找

○ 以此类推

○ 直到 Object.prototype 都没有, 那么返回 null

常见继承计划

  1. 原型链继承

● 实质就是在原型链上做一些手脚, 让某一个对象的 proto 能指向另一个对象就好了

● 外围 : 子类的原型指向父类的实例

// 父类
function Person(name) {this.name = name}
Person.prototype.sayHi = function () {console.log('hello world')
}

// 子类
function Student(age) {this.age = age}

// 实现继承
Student.prototype = new Person('千锋大前端')

const s = new Student(10)
console.log(s)

● 毛病 :

○ 子类没有本人的原型, 因为子类的原型就是父类的实例

○ 在继承属性这方面, 所有子类实例对象继承下来的属性都是截然不同的

● 长处 :

○ 属性和办法都能继承下来

  1. 借用构造函数继承

● 实质就是把父类构造函数当做一个一般函数来应用, 在利用一些扭转 this 指向的办法

● 外围 : 利用 call 或者 apply 办法调用父类构造函数, 让其 this 指向子类的实例

// 父类
function Person(name) {this.name = name}
Person.prototype.sayHi = function () {console.log('hello world')
}

// 子类
function Student(age, name) {
  this.age = age

  // 实现继承
  Person.call(this, name)
}

const s = new Student(10, '千锋大前端')
console.log(s)

● 毛病 :

○ 只能继承父类的属性, 原型上的办法不能继承

● 长处 :

○ 子类有本人的原型, 能够向本人的原型上增加专属于子类的内容

○ 对于继承的属性而言, 每一个子类的实例都会继承一套本人的属性

  1. 根底组合继承

● 实质就是把下面的 原型继承 和 借用构造函数继承 组合在一起应用而已

● 将以上两种继承形式的长处全副合并在一起, 号称最早的完满继承

// 父类
function Person(name) {this.name = name}
Person.prototype.sayHi = function () {console.log('hello world')
}

// 子类
function Student(age) {
  this.age = age

  // 实现继承(目标 : 继承属性)
  Person.call(this, name)

}

// 实现继承(目标 : 继承办法, 属性不重要)
Student.prototype = new Person()

const s = new Student(10, '千锋大前端')
console.log(s)
  1. 寄生继承

● 实质就是是利用一个空对象来包装父类的实例对象,而后再将该空对象的原型设置为父类的原型对象,最初将该空对象返回作为子类的实例对象,从而实现继承。

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

Parent.prototype.sayHi = function() {console.log('hello world')
}

function Student(parent, name) {let student = Object.create(parent)
  student.name = name
  student.sayHello = function() {console.log(`Hello, my name is ${this.name}`)
  }
  return student
}

let parent = new Parent('千锋大前端')
let student = createChild(parent, '千锋大前端')

student.sayHello()
student.sayHi()
  1. 寄生组合继承

● 这是一个十分经典的继承计划, 他是联合了 寄生继承 和 根底组合继承 两者发明进去的. 并且解决了组合继承中反复调用构造函数的难堪, 同时也很好的防止了寄生继承中的原型链净化, 是我集体感觉十分优良得以中继承计划, 不晓得是哪一个大神想进去的计划.

● 在寄生组合继承中,咱们首先应用组合继承的形式创建对象和原型之间的关系,而后通过寄生继承的形式修改原型上不须要的属性

// 寄生继承实现函数
function inheritPrototype(student, person) {
  // 创立父类原型的一个正本
  let prototype = Object.create(person.prototype)
  // 修改正本的 constructor 属性
  prototype.constructor = student
  // 将修改后的原型赋值给子类
  student.prototype = prototype
}

// 父类
function Person(name) {this.name = name}
Person.prototype.sayHi = function() {console.log('hello world')
}

// 子类
function Student(age, name) {
  this.age = age
  // 借用继承(目标 : 继承属性)
  Person.call(this, name)
}

// 寄生继承
inheritPrototype(Student, Person)

// 向子类本人的原型上增加办法
Student.prototype.sayHello = function() {console.log(`Hello, My name is ${ this.name}`);
}

let instance = new Student(10, '千锋大前端')
instance.sayHello()
instance.sayHi()
  1. ES6 的类继承语法

● 在 ES6 标准中, 呈现了类继承的语法

● 也就是说, 咱们能够不须要以上这些乌七八糟的玩意了, 间接上语法

● 咱们能够间接应用 extends 关键字进行父类的继承

○ 留神 : 还须要在类的结构器内写一个 super 来继承父类属性

// 父类
class Person {constructor(name) {this.name = name;}

  sayHi () {console.log('Hello world')
  }
}

// 子类, 间接应用 extends 关键字继承父类
class Student extends Person {constructor(name, age) {
    // 继承父类属性
    super(name)
    this.age = age
  }

  sayAge() {console.log(`Hello, My name is ${ this.name}`)
  }
}

let instance = new Student('千锋大前端', 10)
instance.sayHello()
instance.sayHi()
退出移动版