有这样一个函数, 我们根据传入的第一个参数类型不同, 以不同方式执行相同操作 (单分派泛函数), 我们来看一个简单的例子:
- function show(value) {
- if(value instanceof Array) {
- console.log(value.join('-'));
- } else if(value instanceof Date) {
- console.log(value * 1);
- } else if (value instanceof Number || value instanceof Boolean) {
- console.log(value * value)
- } else {
- console.log(value);
- }
- }
这个例子比较简单, 每一个 if 后面只有一行代码, 然而在实际工作中, 也许每一个 if 后面都有一段逻辑复杂逻辑复杂的代码, 我们通常的处理方式就是将其拆分出来作为一个新的函数, 然后在 if 里面调用, 现在我向大家介绍一种新的方法来出来这种情况.
我们先来看看使用方式:
- const show = singledispatch(vlaue => console.log(value));
- show
- .dispatch(value => console.log(value * value))
- .register(Number)
- .register(Boolean);
- .dispatch(value => console.log(value * 1))
- .register(Date);
- .dispatch(value => console.log(value.join('-')))
- .register(Array);
- show(2); // 4
- show(true); // 1
- show([3, 4, 5]) // 3-4-5
- show(new Date()) // 1542177163659
- show({a: 1}) // [object Object]
singledispatch 接受一个函数, 返回一个函数对象 show,show 先 dispatch 一个函数, 之后注册一个 Number 和 Boolean, 表示 show 传入的参数如果是数字或者布尔类型, 就调用 dispatch 的这个函数, 之后也是这样.
singledispatch 需要返回一个函数对象, 我们假设叫 out, 这个函数对象有两个方法分别为 dispatch 和 register, 链式调用就需要返回 out; 具体实现过程如下,
- function singledispatch(fn /* 默认是一个空函数 */ = Function.prototype) {
- let current; // 用于记录啊 dispatch 的函数
- let registry = {}; // 一个对象, 用于存储某个类型下对应调用的函数
- function out(arg){
- let type = Object.prototype.toString.call(arg);
- if(registry[type]) {
- return registry[type](arg);
- } else {
- return fn(arg);
- }
- }
- out.dispatch = function dispatch(f) {
- if(typeof f !== 'function') {
- throw Error('some error')
- }
- current = f;
- return out;
- }
- out.register = function register(ctor) {
- if(!current) {
- throw Error('register 必须在 dispatch 之后调用')
- }
- registry[`[object ${ctor.name}]`] = current;
- return out
- }
- return out;
- }
有的时候, 我们并不是根据类型做判断, 我们希望可以自定义的方式去判断, 因此, register 可以传入一个函数, 用这个函数去做判断, 就像下面这个样子:
- const f = singledispatch();
- f
- .dispatch(v => v * v * v).register(v => v> 10)
- .dispatch(v => v * v).register(v => v <= 10);
- f(11) // 1331
- f(5) // 25
此时的 singledispatch 需要修改 register 和 out:
- function singledispatch(fn = Function.prototype) {
- let current;
- let registry = [];
- let conditions = []
- function out(arg){
- let index = conditions.findIndex(f => f(arg));
- if(index>= 0) {
- return registry[index](arg);
- } else {
- return fn(arg);
- }
- }
- out.dispatch = function dispatch(f) {
- if(typeof f !== 'function') {
- throw Error('some error')
- }
- current = f;
- return out;
- }
- out.register = function register(condition) {
- if(!current) {
- throw Error('register 必须在 dispatch 之后调用')
- }
- if(typeof condition !== 'function') {
- throw Error('some error')
- }
- conditions.push(condition);
- registry.push(current);
- return out
- }
- return out;
- }
来源: https://juejin.im/post/5bebc038e51d45787a4bb85b