为什么有类?

  • 不同对象的属性重复了,就有了类

    1. let person1 = {
    2. name:'gouson',age:19,sayHi(){}
    3. }
    4. let person2 = {
    5. name:'mengmeng',age:18,sayHi(){}
    6. }
  • 类和构造函数

    1. class Person{
    2. name
    3. age
    4. sayHi(){}
    5. constructor(name,age){
    6. this.name=name
    7. this.age=age
    8. }
    9. }
    10. let person1 = new Person('gouson',19)
    11. let person2 = new Person('mengmeng',18)

    改为TypeScript

  • 类+数据类型

    1. class Person{
    2. sayHi:void{}
    3. constructor(public name:string,public age:number){}
    4. }
    5. let person1 = new Person('gouson',19)
    6. let person2 = new Person('mengmeng',18)

    小结

    • 类是把对象得属性提前写好,避免重复
    • 类里面的字段会变成对象得属性
    • 为了节约内存,所有函数都是共用的
      • 但是如果 mySayHi=()=>{}//就是自用的函数
    • 而非函数属性是对象各自有的
      • 但是要创建一个共有属性可以
      • 在原型上加 Person.prototype.kind=’people’
      • static kind = ‘people’
    • 使用console.log(person1)可以看到
  • 构造函数
    • 属性名虽然可以提前写好,但是属性值不可以
    • 需要构造函数接受参数,初始化属性值
    • 构造函数不需要写return,默认会return新对象
  • 语法

继承

为什么有继承

  • 不同的类的属性重复了,就有了继承

现在要给Person添加功能

  • person1.on(‘die’,fn)
  • person1.emit(‘die’)
  • person1.off(‘die’,fn)
  • 就是让Person具有发布订阅功能

    1. class Person{
    2. constructor(public name){}
    3. sayHi(){}
    4. cache=[]
    5. on(){}
    6. off(){}
    7. emit(){}
    8. }

    如果现在Animal类也要拥有发布订阅功能

    1. class Animal{
    2. constructor(public name){}
    3. roar(){}
    4. cache=[]//重复
    5. on(){}//重复
    6. off(){}//重复
    7. emit(){}//重复
    8. }

    这时候,两个类的发布订阅属性重复了
    现可以通过继承来解决这个问题

  • 把重复属性拿出来单独写个类EventEmitter

  • 然后让Person和Animal类来继承
  • 注意constructor要调用super()来保证EventEmitter实例被初始化
    1. class EventEmitter{
    2. constructor(){}
    3. cache=[]//重复
    4. on(){}//重复
    5. off(){}//重复
    6. emit(){}//重复
    7. }
    8. class Person extends EventEmitter{
    9. constructor(public name){
    10. super()
    11. }
    12. sayHi(){}
    13. }
    14. class Animal extends EventEmitter{
    15. constructor(public name){
    16. super()
    17. }
    18. roar(){}
    19. }
    20. const person=new Person()
    21. const animal=new Animal()

    重写

    子类重写父类的所有属性,以实现多态
    多态的意思是不同的子类对同一个消息有不同的反应
    1. class Person extends EventEmitter{
    2. constructor(public name){
    3. super()
    4. }
    5. sayHi(){}
    6. on(eventName,fn){
    7. console.log('开始监听')
    8. super.on(eventName,fn)
    9. }
    10. }

    继承的问题

    如果需要更多的功能,一是让EventEmitter继承其他类,二是让Person继承两个类(多继承)
    这两种方法其实都不好,用到组合

    组合

组合没有固定写法

  1. class Person{
  2. eventEmitter = new EventEmitter()
  3. name
  4. sayHi(){}
  5. on(eventName,fn){
  6. this.eventEmitter.on(eventName,fn)
  7. }
  8. off(eventName,fn){
  9. this.eventEmitter.off(eventName,fn)
  10. }
  11. emit(eventName,fn){
  12. this.eventEmitter.emit(eventName,fn)
  13. }
  14. }

上面的代码还可以优化一下

  1. class Person{
  2. name
  3. sayHi(){}
  4. }
  5. let person1 = new Person('Gouson')
  6. mixin(person1,new EventEmitter())
  7. function mixin(to,from){//这是最简化的mixin,实际会更复杂
  8. for(let key in from){
  9. to[key] = from[key]
  10. }
  11. }

如果需要更多的功能

  1. class Person{
  2. name
  3. sayHi(){}
  4. }
  5. let person1 = new Person('frank')
  6. mixin(person1, new EventEmitter())
  7. mixin(person1, new Flyer())
  8. mixin(person1, new Killer())

例子

dog
.wangwang()
.poop()

cat
.miaomiao()
.poop()

animal
.poop()
dog
.wangwang()
cat
.miaomiao()

cleaningRobot
.run()
.clean()

murderRobot
.run()
.kill()

robot
.run()
cleaningRobot
.clean()
murderRobot
.kill()

不用class写dog

  1. const createWang = (state) => ({
  2. wangwang: ()=> {
  3. console.log(`汪汪,我是 ${state.name}`)
  4. }
  5. })
  6. const createRun = (state) => ({
  7. run: ()=> state.position += 1
  8. })
  9. const createDog = (name) => {
  10. const state = {name, position: 0}
  11. return Object.assign(
  12. {},
  13. createWang(state),
  14. createRun(state)
  15. )
  16. }
  17. const dog = createDog('小白')

需要一个狗型杀人机器人,不需要poop(),用继承很难做到,所以要用到组合

dog=poop()+wangwang()
cat=poop()+miaomiao()
cleaningRobot=run()+clean()
murderRobot=run()+kill()
KillerDogRobot=run()+kill()+wangwang()

  1. const createMurderRobotDog = (name) => {
  2. const state = {name, position: 0}
  3. return Object.assign(
  4. {},
  5. createWang(state),
  6. createRun(state),
  7. createKill(state)
  8. )
  9. }
  10. const murderRobotDog = createMurderRobotDog(' ')

什么情况下用继承

  • 开发者不会用组合
  • 功能没有太多的交叉,一眼就能看出继承关系
  • 前端库比较喜欢用继承
  • 举例

    • const vm = new Vue({…})
    • class App extends React.Component{…}
    • React.Component 内置了方便的复用代码(轮子)

      什么情况下用组合

  • 功能组合非常灵活,无法一眼看出继承关系

  • 插件系统
  • mixin模式
  • 举例
    • Vue.mixin()
    • Vue.use(MyPlugin)
    • React接受组件的组件