有这样一个函数,我们根据传入的第一个参数类型不同,以不同方式执行相同操作(单分派泛函数), 我们来看一个简单的例子:
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;
}
复制代码