js中的继承

js中的继承

箭头函数与普通函数中的 this 指向

首先引入一道面试题:

let name = 'Tom'
function Person() {
  this.name = 'Jack'
  this.say = () => {
    console.log('my name is ' + this.name)
  }
}

let P = new Person()
let func = P.say
func()
// 'Jack'
let name = 'Tom'
function Person(name) {
  this.name = 'Jack'
  this.say = function() {
    console.log('my name is ' + this.name)
  }
}

let P = new Person()
let func = P.say
func()
// 'Tom'

题目解析:

两道题目的区别在于构造函数中,定义方法时使用的函数声明方式不同,前者使用 箭头函数 ,后者使用 普通函数 ,而箭头函数与普通函数的区别在于: 执行时 this 的指向不同

  1. 箭头函数:箭头函数的 this 指向在 函数声明时即创建 ,理解为在定义函数的上下文中获取函数中的 this 指向。如题一中,虽然将函数整体赋值给变量 func ,但在函数调用的时候,仍然在箭头函数定义时的上下文中去查找 this ,即指向 Person 的实例化对象 P ,找到该对象的 name 属性,故打印 ‘Jack’
  2. 普通函数:普通函数的 this 指向在 函数调用时查找 。如题二,将函数整体赋值给变量 func ,相当于重新声明了一个函数名为 func 的函数,该函数在调用时与原构造函数和实例化对象都没有关系了,所以其中的 this 指向会向执行上下文中查找,故打印 ‘Tom’

ES5 继承

关于继承,简单来理解就是子类需要用到父类的属性和方法,而不用子类重新定义

如下代码中:

定义了一个 Person 类,我们希望 Student 类继承自 Person 类,并可以获取到 Person 类的 name/job/arr 属性 say 方法,但我们希望可以自己定义 job 为 ‘学生’

// Person 类:name/job/arr 属性,say 方法
function Person(name, job) {
  this.name = name
  this.job = job
  this.arr = [1, 2, 3]
  this.say = function() {
    // 介绍自己的姓名和职业
    console.log(`My name is ${this.name}, I'm a ${this.job}.`)
  }
}

function Student() {}
  1. 构造函数继承

    // Person 类:name/job/arr 属性,say 方法
    function Person(name, job) {
      this.name = name
      this.job = job
      this.arr = [1, 2, 3]
      this.say = function() {
        // 介绍自己的姓名和职业
        console.log(`My name is ${this.name}, I'm a ${this.job}.`)
      }
    }
    
    Person.prototype.on = 'on'
    
    function Student(name) {
      Person.call(this, ...arguments)
      this.job = 'student'
    }
    
    var s1 = new Student('Jack')
    var s2 = new Student('Tom')
    

    此时的一个缺陷是:

    • 若 Person 类的原型对象,即 prototype 上也定义了方法,那将无法继承到。如 Person.prototype.on 上的 ‘on’ 属性
  2. prototype 继承

    // Person 类:name/job/arr 属性,say 方法
    function Person(name, job) {
      this.name = name
      this.job = job
      this.arr = [1, 2, 3]
      this.say = function() {
        // 介绍自己的姓名和职业
        console.log(`My name is ${this.name}, I'm a ${this.job}.`)
      }
    }
    
    function Student(name) {
      this.name = name
      this.job = 'student'
    }
    
    Student.prototype = new Person()
    Student.prototype.constructor = Student 
    
    var s1 = new Student('Jack')
    var s2 = new Student('Tom')
    

    将 Student 的 prototype 属性指向 Person 的实例,当 Student 的实例没有找到属性时,会在 prototype 中寻找,但此时的问题有:

    • 父类需要传入参数时,不能在 new Person() 中传入,只能在子类中重新写
    • 所有的 Student 实例都会查找同一个 prototype ,所以不可以修改子类继承自父类的属性,如代码中的 arr ,一处修改会影响所有内容
    • prototype.constructor 指向它本身的构造函数,修改以后要重新赋值
  3. 组合继承

    // Person 类:name/job/arr 属性,say 方法
    function Person(name, job) {
      this.name = name
      this.job = job
      this.arr = [1, 2, 3]
      this.say = function() {
        // 介绍自己的姓名和职业
        console.log(`My name is ${this.name}, I'm a ${this.job}.`)
      }
    }
    
    Person.prototype.on = 'on'
    
    function Student(name) {
      Person.call(this, ...arguments)
      this.job = 'student'
    }
    
    Student.prototype = new Person()
    Student.prototype.constructor = Student 
    
    var s1 = new Student('Jack')
    var s2 = new Student('Tom')
    

    组合继承结合两种方法,实现继承。首先在构造函数内执行父类代码,再通过原型链获取到父类构造函数的原型对象 prototype 上定义的不变的属性和方法

ES6 继承

// Person 类:name/job/arr 属性,say 方法
class Person {
  constructor (name, job) {
    this.name = name
    this.job = job
    this.arr = [1, 2, 3]
  }

  say = function() {
    // 介绍自己的姓名和职业
    console.log(`My name is ${this.name}, I'm a ${this.job}.`)
  }
}

class Student extends Person {
	constructor () {
    super()
    this.job = 'student'
  }
}

var s1 = new Student('Jack')
var s2 = new Student('Tom')

ES6 中通过关键字 extends 可以实现继承,如代码中, s1 和 s2 已经继承了Person 类中的属性和方法

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值