0.3.0 • Published 8 months ago

overload-in-js v0.3.0

Weekly downloads
-
License
MIT
Repository
-
Last release
8 months ago

在JavaScript中使用重载

Version 0.3.0


引入

    // mjs 引入
    import { overload } from 'overload-in-js';
    // cjs 引入
    const { overload } = require('overload-in-js');

如何使用

基础功能

  overload(f): overload; // 无参函数重载
  overload(types..., f): overload; // 有参函数重载
  overload(): polymerization; // 最终生成聚合函数

overload需要输入一组类型名称,它们分别对应重载函数形参列表,类型名指定后要在末尾设置重载函数。一组重载定义完成后可以接着后面定义新的一组重载,格式也完全一样。当所有的重载都定义完成时需要不传任何值执行一次,该过程会生成一个聚合函数,当我们调用聚合函数时会根据输入参数的类型自动匹配运行其内部的重载函数。

    import { overload } from 'overload-in-js';

    const add = overload('number', 'number', function(a, b) {
        return a + b;
    })('string', 'string', function(a, b) {
        return Number(a) + Number(b);
    })();

    add(1, 2); // 3
    add('1', '2'); // 3

如果我们在指定参数类型时需要用到自定义对象,您可以像下面这样进行定义。

    import { overload } from 'overload-in-js';

    function PNumber(value) {
        this.value = value
    } // 用class定义也可以。

    const add = overload(PNumber, PNumber, function(a, b) {
        return a.value + b.value;
    })();

    add(new PNumber(1), new PNumber(2)); // 3

需要注意的是有时候我们很容易将Number、String这样函数误当成类型直接传入,请使用'number', 'string' 等样式字符串来指定基本数据类型,您也可以参考文档最后的类型表。

使用 autoLength 钩子

上面这些可以明确知道每种类型参数的个数,这种类型的重载我称它匹配重载。有时候一些参数可能不固定,面对这种情况我们将使用autoLength来包装参数类型此时重载就变成了通项重载。只要参数列表中有一个使用了autoLength包装,那么这一条重载都将变为通项重载。

    import { overload, autoLength } from 'overload-in-js';

    // 纯数字
    const add = overload(autoLength('number'), function(...values) {
        return values.reduce((total, v) => total + v, 0);
    })
    // 字符串 + 数字
    (autoLength('string'), autoLength('number'), function(...values) {
        return values.reduce((pre, v) => pre + v, '');
    })
    // 数字 + 字符串。这是一次指定多个类型的写法
    (autoLength('number', 'string'), function(...values) {
        return values.reduce((pre, v) => pre + Number(v), 0);
    })();

    add(1, 2, 3, 4); // 10
    add('1', '2', 3, 4); // '1234'
    add(6, 7, '5'); // 18

注意: autoLength仅用于重载定义阶段,执行阶段直接使用会报错。同时请勿滥用通项重载,复杂的通项重载会让代码辨识度降低造成逻辑混乱导致重载覆盖。

使用 typeNone 钩子

假设存在这种情况,可执行函数形参是一个可选参数,如果我们仅传入一个值,如下。

    import { overload } from 'overload-in-js';
    const add = overload('number', 'number', (a = 0, b = 1) => a + b)();

    add(1); // error

那么毫无疑问执行聚合函数的时候会报错。但我们又希望在传入一个值的时候触发该函数,该怎么解决呢?typeNone钩子就用于解决这一问题,它就像一个带有类型的undefined,仅用于匹配形参类型但不表示任何值。使用方式如下。

    import { overload, typeNone } from 'overload-in-js';
    const add = overload('number', 'number', (a = 0, b = 1) => a + b)();

    add(typeNone('number'), 5); // 0 + 5 = 5
    add(3, typeNone('number')); // 3 + 1 = 4
    add(typeNone('number'), typeNone('number')); // 0 + 1 = 1

注意: typeNone仅用于聚合函数执行阶段,在重载定义阶段直接使用则会报错。

细节

匹配重载即每一个类型都匹配上才会执行相应的重载函数。而通项重载则是一个不确定长度的重载,一定范围内只要输入的参数类型不发生改变那么就会匹配,当所有条件满足的时候执行相应的重载函数。

当我们调用聚合函数的时候,overload会优先按照匹配重载的规则寻找符合条件的函数并执行。如果没有找到就会按照通项重载的规则查找相应的重载函数并执行。如果前两个都没有找到就会报错。

通过上面的解释我们会发现优先级:匹配重载 > 通项重载。没错,所以我们在通过它们进行编码时应当注意如果可以确定每个参数长度的尽量用匹配重载,不当的使用通项重载会产生冗余的运算。

当然有一种情形除外,如果我们输入的参数个数大于所有匹配重载最长的参数个数,那么overload会直接按照通项重载来寻找重载函数。

如果不知道类型怎么办?

一些基础类型您可以使用typeof来查询它们。如果是对象类型您需要直接传入它们的构造函数。下面是一些常见的参数类型列表。

类型输入样本
nullnullnull
undefinedvoid 0undefined
bool'boolean'true,false
number'number'1,NaN,Infinity
string'string''1'
function'function'Number,String, function f() {}
generator'function'function* g() {}
async function'function'async function af() {}
symbol'symbol'Symbol(1)
bigint'bigint'1n
arrayArray[1,2,3],new Array()
RegExpRegExp/^[123].txt$/
ObjectObject{}
PromisePromisenew Promise()
0.3.0

8 months ago

0.2.2

8 months ago

0.2.1

8 months ago