(JavaScript)Mixin 模式

Mixin 模式

  • JavaScript 中,我们只能继承单个对象。每个对象只能有一个 [[Prototype]]。并且每个类只可以扩展另外一个类。
  • mixin 是一个包含可被其他类使用而无需继承的方法的类。

一个 Mixin 实例

  • 最简单的构造mixin方式:构造一个拥有实用方法的对象
// 创建一个对象来构造minin
let sayHiMixin = {
  sayHi() {
    alert(`Hello ${this.name}`);
  },
  sayBye() {
    alert(`Bye ${this.name}`);
  }
};

// 用法:
class User {
  constructor(name) {
    this.name = name;
  }
}

// 拷贝方法
Object.assign(User.prototype, sayHiMixin);

// 现在 User 可以打招呼了
new User("Dude").sayHi(); // Hello Dude!
  • 上面的代码只包含简单方法的拷贝。所以User还可以继承另一个类。mixin和继承可以共存。
class User extends Person {
  // ...
}

Object.assign(User.prototype, sayHiMixin);
  • Minin 可以在自己的内部使用继承
let sayMixin = {
  say(phrase) {
    alert(phrase);
  }
};

let sayHiMixin = {
  __proto__: sayMixin, // (或者,我们可以在这儿使用 Object.create 来设置原型)

  sayHi() {
    // 调用父类方法
    super.say(`Hello ${this.name}`); // (*)
  },
  sayBye() {
    super.say(`Bye ${this.name}`); // (*)
  }
};

class User {
  constructor(name) {
    this.name = name;
  }
}

// 拷贝方法
Object.assign(User.prototype, sayHiMixin);

// 现在 User 可以打招呼了
new User("Dude").sayHi(); // Hello Dude!
注意:
  • 当把sayHiMixin中的方法复制到User.prototype中去的时候,[[Homeobject]]内部属性仍旧引用的是sayHiMixin。也就是表面上是new User("Dude").sayHi();实际上是 sayHiMixin.sayHi()。所以,当super[[HomeObject]].[[Prototype]] 中寻找父方法时,意味着它搜索的是 sayHiMixin.[[Prototype]],而不是 User.[[Prototype]]。
    在这里插入图片描述

EventMixin

  • 构造一个mixin,将与事件相关的函数添加到任意 class/object

Mixin提供的方法

  • .trigger(name, [...data]):在发生重要事情的时候生成一个事件
  • .on(name, handler):为具有给定名称的事件添加了 handler 函数作为监听器,当具有给定 name 的事件触发时将调用该方法,并从 .trigger 调用中获取参数。
  • .off(name, handler):删除 handler 监听器
let eventMixin = {
  /**
   * 订阅事件,用法:
   *  menu.on('select', function(item) { ... }
   *  _eventHandlers属性:储存每个事件名称对应的处理程序(handler)
  */
  on(eventName, handler) {
    //如果还没有_eventHandlers属性,就创建一个
    if (!this._eventHandlers) this._eventHandlers = {};
    //如果这个名称的事件不存在,就创建一个
    if (!this._eventHandlers[eventName]) {
      this._eventHandlers[eventName] = [];
    }
    //在_eventHandlers属性添加这个名称的事件对应的处理程序
    this._eventHandlers[eventName].push(handler);
  },

  /**
   * 取消订阅,用法:
   *  menu.off('select', handler)
   * 从处理程序列表中删除指定的函数
   */
  off(eventName, handler) {
    //this._eventHandlers如果存在,获取它的[eventName]
    let handlers = this._eventHandlers?.[eventName];
    if (!handlers) return;
    for (let i = 0; i < handlers.length; i++) {
      if (handlers[i] === handler) {
        //第一个参数是删除的位置,第二个参数是删除的数量
        handlers.splice(i--, 1);
      }
    }
  },

  /**
   *  生成具有给定名称和数据的事件
   *  this.trigger('select', data1, data2);
   */
  trigger(eventName, ...args) {
    if (!this._eventHandlers?.[eventName]) {
      return; // 该事件名称没有对应的事件处理程序(handler)
    }

    // 调用事件处理程序(handler)
    this._eventHandlers[eventName].forEach(handler => handler.apply(this, args));
  }
};

用法:

// 创建一个 class
class Menu {
  choose(value) {
    this.trigger("select", value);
  }
}
// 添加带有事件相关方法的 mixin
Object.assign(Menu.prototype, eventMixin);

let menu = new Menu();

// 添加一个事件处理程序(handler),在被选择时被调用:
menu.on("select", value => alert(`Value selected: ${value}`));

// 触发事件 => 运行上述的事件处理程序(handler)并显示:
// 被选中的值:123
menu.choose("123");
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值