[关闭]
@15013890200 2019-07-05T11:28:36.000000Z 字数 5038 阅读 483

js 继承实现及特点

继承 原型 原生js

js实现继承的方式有多种,每种方式都有自己适合的场景,也都有各自的优缺点
本文主要介绍7种继承实现方式(原型链继承、借用构造函数、组合方式、原型式继承、寄生式继承、寄生组合式继承、class实现),并附上例子


1、原型链继承

  1. ;(() => {
  2. /**
  3. * 原型链继承
  4. * 原型会变成另一个类型的实例
  5. * 该原型的引用类型属性会被所有的实例共享
  6. * 创建子类型实例的时候,没有办法在不影响所有对象实例的情况下给超类的构造函数中传递参数
  7. */
  8. console.log('----------原型链继承----------')
  9. function Person () {
  10. this.name = 'person'
  11. this.hobby= ['game', 'sport']
  12. }
  13. Person.prototype.getName = function () {
  14. console.log(this.name)
  15. }
  16. Person.prototype.getHobby = function () {
  17. console.log(this.hobby)
  18. }
  19. let p1 = new Person()
  20. function Chinese () {
  21. this.country = 'china'
  22. }
  23. Chinese.prototype = new Person()
  24. Chinese.prototype.constructor = Chinese
  25. Chinese.prototype.getCountry = function () {
  26. console.log(this.country)
  27. }
  28. let p2 = new Chinese()
  29. let p3 = new Chinese()
  30. p3.getHobby()
  31. p2.getHobby()
  32. p2.hobby.push('swim')
  33. p2.getHobby()
  34. p3.getHobby() // ['game', 'sport', 'swim']
  35. p1.getHobby() // ['game', 'sport']
  36. console.log(p2 instanceof Person) // true
  37. console.log(p2 instanceof Chinese) // true
  38. console.log(p2 instanceof Object) // true
  39. console.log('--------------------')
  40. })();

2、借用构造函数

  1. ;(() => {
  2. /**
  3. * 借用构造函数继承
  4. * 可以向超类传递参数
  5. * 解决了原型中包含引用类型值被共享的问题
  6. * 超类型的原型对于子类型是不可见的
  7. */
  8. console.log('----------构造函数继承----------')
  9. function Person (name) {
  10. this.name = name
  11. this.hobby= ['game', 'sport']
  12. }
  13. Person.prototype.getName = function () {
  14. console.log(this.name)
  15. }
  16. Person.prototype.getHobby = function () {
  17. console.log(this.hobby)
  18. }
  19. let p1 = new Person('p1')
  20. function Chinese (name) {
  21. Person.call(this, name)
  22. this.country = 'china'
  23. }
  24. Chinese.prototype.getCountry = function () {
  25. console.log(this.country)
  26. }
  27. let p2 = new Chinese('p2')
  28. let p3 = new Chinese('p3')
  29. // p2.getHobby() 不可用
  30. p2.getCountry()
  31. console.log(p1.name) // p1
  32. console.log(p2.name) // p2
  33. console.log(p2.hobby)
  34. console.log(p3.hobby)
  35. p2.hobby.push('swim')
  36. console.log(p2.hobby)
  37. console.log(p3.hobby) // ['game', 'sport']
  38. console.log('--------------------')
  39. })();

3、组合式继承(原型链+构造函数)

  1. ;(() => {
  2. /**
  3. * 构造函数 + 原型链(组合继承)
  4. * 任何情况下,都会调用两次超类型构造函数
  5. * 可以向超类传递参数
  6. * 每个实例都有自己的属性
  7. * 实现了函数复用
  8. */
  9. console.log('----------组合式继承----------')
  10. function Person (name) {
  11. this.name = name
  12. this.hobby= ['game', 'sport']
  13. }
  14. Person.prototype.getName = function () {
  15. console.log(this.name)
  16. }
  17. Person.prototype.getHobby = function () {
  18. console.log(this.hobby)
  19. }
  20. let p1 = new Person()
  21. function Chinese (name, country) {
  22. Person.call(this, name) // 1次
  23. this.country = country
  24. }
  25. Chinese.prototype = new Person() // 2次
  26. Chinese.prototype.constructor = Chinese
  27. Chinese.prototype.getCountry = function () {
  28. console.log(this.country)
  29. }
  30. let p2 = new Chinese('p2', 'anhui')
  31. let p3 = new Chinese('p3', 'guangdong')
  32. // p2.getHobby() 不可用
  33. p2.getCountry() // anhui
  34. p2.getName() // p2
  35. p3.getCountry() // guangdong
  36. console.log(p2.hobby)
  37. console.log(p3.hobby)
  38. p2.hobby.push('swim')
  39. console.log(p2.hobby)
  40. console.log(p3.hobby) // ['game', 'sport']
  41. console.log('--------------------')
  42. })();

4、原型式继承

  1. ;(() => {
  2. /**
  3. * 原型式继承
  4. * 适用于没有必要创建构造函数,仅让一个对象与另一个对象保持相似
  5. * 同原型链实现继承一样,引用类型值会被所有实例共享
  6. */
  7. console.log('----------原型式继承----------')
  8. let person = {
  9. name: 'person',
  10. hobby: ['game', 'sport']
  11. }
  12. let p1 = Object.create(person)
  13. // es5之后通过Object.create(o),之前如下
  14. // function create (o) {
  15. // function F () {}
  16. // F.prototype = o
  17. // return new F()
  18. // }
  19. p1.name = 'p1'
  20. p1.hobby.push('swim')
  21. console.log(p1.hobby)
  22. let p2 = Object.create(person)
  23. p2.name = 'p2'
  24. console.log(p2.hobby)
  25. p2.hobby.push('sing')
  26. console.log(p1.name)
  27. console.log(p2.name)
  28. console.log(p1.hobby)
  29. console.log(p2.hobby)
  30. console.log('--------------------')
  31. })();

5、寄生式继承

  1. ;(() => {
  2. /**
  3. * 寄生式继承
  4. * 创建一个仅用于封装过程的函数,在内部来增强对象
  5. * 适用于对象不是自定义类型和构造函数的情况下
  6. * 不能做到函数复用而效率低下
  7. * 与原型链原型式继承一样,引用类型值会被共享
  8. */
  9. // function create (o) {
  10. // function F () {}
  11. // F.prototype = o
  12. // return new F()
  13. // }
  14. console.log('----------寄生式继承----------')
  15. function Person (p) {
  16. let clone = Object.create(p)
  17. clone.getName = function () {
  18. console.log('hi')
  19. }
  20. return clone
  21. }
  22. var p1 = {
  23. name: 'p1',
  24. hobby: ['game', 'sport']
  25. }
  26. let p2 = Person(p1)
  27. p2.getName() // hi
  28. console.log(p1)
  29. console.log(p2)
  30. console.log(p2.name) // p1
  31. console.log('--------------------')
  32. })();

6、寄生组合式继承

  1. ;(() => {
  2. /**
  3. * 寄生组合式继承
  4. * 不必为了指定子类型的原型而调用超类型的构造函数,只调用了一次超类构造函数,效率更高
  5. * 原型链保持一致
  6. * 最理想的继承范式
  7. */
  8. console.log('----------寄生组合式继承----------')
  9. function inherit (subType, superType) {
  10. let prototype = Object.create(superType.prototype) // 拷贝超类对象原型
  11. prototype.constructor = subType // 指定构造对象
  12. subType.prototype = prototype // 挂载原型
  13. }
  14. function SuperType (name) {
  15. this.name = name
  16. this.hobby = ['game', 'sport']
  17. }
  18. SuperType.prototype.getName = function () {
  19. console.log(this.name)
  20. }
  21. SuperType.prototype.getHobby = function () {
  22. console.log(this.hobby)
  23. }
  24. function SubType (name, country) {
  25. SuperType.call(this, name)
  26. this.country = country
  27. }
  28. SubType.prototype.getCountry = function () {
  29. console.log(this.country)
  30. }
  31. inherit(SubType, SuperType)
  32. let s1 = new SuperType('s1')
  33. let s2 = new SubType('s2', 'anhui')
  34. let s3 = new SubType('s3', 'guangdong')
  35. console.log(s1)
  36. console.log(s2)
  37. console.log(s3)
  38. s2.hobby.push('swim')
  39. s2.getHobby()
  40. s3.getHobby()
  41. s2.getName()
  42. console.log('--------------------')
  43. })();

7、class实现

  1. ;(() => {
  2. /**
  3. * class(es6)实现继承
  4. * 语法糖,本质上还是通过原型实现继承
  5. */
  6. console.log('----------class继承----------')
  7. class SuperType {
  8. constructor (name) {
  9. this.name = name
  10. this.hobby = ['game', 'sport']
  11. }
  12. getName () {
  13. console.log(this.name)
  14. }
  15. getHobby () {
  16. console.log(this.hobby)
  17. }
  18. }
  19. class SubType extends SuperType {
  20. constructor(name, country) {
  21. super(name)
  22. this.country = country
  23. }
  24. getCountry () {
  25. console.log(this.country)
  26. }
  27. }
  28. let s1 = new SuperType('s1')
  29. let s2 = new SubType('s2', 'anhui')
  30. let s3 = new SubType('s3', 'guangdong')
  31. console.log(s1)
  32. console.log(s2)
  33. console.log(s3)
  34. s2.hobby.push('swim')
  35. s2.getHobby()
  36. s3.getHobby()
  37. s3.getName()
  38. s2.getCountry()
  39. })();
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注