js 函数重载 override/overloading/createOverload

JavaScript中的函数重载(Function overloading)
更新于: 2023-09-10 13:08:49

场景

一个多种方式调用的 getUsers 实现。

已经添加到 next@1.1.12 中 nx.createOverload 方法

场景再现

通常实现

即通常我们没有 createOveride 的实现方式,非优雅的实现。

function getUsers(...args) {
  const len = args.length;
  const types = args.map((item) => typeof item).join();
  switch (true) {
    // get by id
    case len === 1 && types === 'number':
      console.log('get by id');
      break;
    case len === 1 && types === 'string':
      console.log('get by name');
      break;
    case len === 2 && types === 'string,number':
      console.log('get by name and age');
      break;
    default:
      console.log('get all');
  }
}

推荐

一种更优雅、通用的写法

function createOverload() {
  const callMap = {};
  function overload(...args) {
    const key = args.map((item) => typeof item).join();
    const fn = callMap[key];
    if (!fn) throw new Error('没有匹配的函数');
    return fn(...args);
  }

  overload.add = function (...args) {
    const fn = args.pop();
    const types = args.join();
    if (typeof fn !== 'function') {
      throw new Error('最后一个参数必须是函数');
    }
    callMap[types] = fn;
  };

  return overload;
}

const getUsers = createOverload();

getUsers.add('number', function (id) {
  console.log('get by id');
});

getUsers.add('string', function (name) {
  console.log('get by name');
});

getUsers.add('string,number', function (name, age) {
  console.log('get by name and age');
});

getUsers.add('', function () {
  console.log('get all');
});

getUsers();
getUsers(1);
getUsers('1');
getUsers('1', 1);

优化

  • 优化报错
  • 优化 add 方法时候传参
function createOverload() {
  const callMap = {};

  function overload(...args) {
    const key = args.map((item) => typeof item).join();
    const fn = callMap[key];
    if (!fn) {
      throw new Error(`没有匹配的函数,参数类型: [${key}]`);
    }
    return fn(...args);
  }

  overload.add = ({ args, fn }) => {
    if (typeof fn !== 'function') {
      throw new Error('最后一个参数必须是函数');
    }
    const types = args.join();
    callMap[types] = fn;
  };

  return overload;
}

const getUsers = createOverload();

getUsers.add({
  args: [],
  fn: function () {
    console.log('get all');
  }
});

getUsers.add({
  args: ['number'],
  fn: function (id) {
    console.log('get by id');
  }
});

getUsers.add({
  args: ['string'],
  fn: function (name) {
    console.log('get by name');
  }
});

getUsers.add({
  args: ['string', 'number'],
  fn: function (name, age) {
    console.log('get by name and age');
  }
});

getUsers(); 				// get all
getUsers(1); 				// get by id
getUsers('tom'); 			// get by name
getUsers('tom', 18); 		// get by name and age

实战

重构 keyMap 方法

const nx = require('@jswork/next');

const keyMap = nx.createOverload();

// 只有一个参数,并且参数为 array
keyMap.add({
  args: ['array'],
  fn: function (inArray) {
    return inArray.map((item) => {
      return { value: item, label: item };
    });
  }
});

// 将目标重构为2个array的情况
keyMap.add({
  args: ['array', 'array'],
  fn: function (inArray1, inArray2) {
    return inArray1.map((item) => {
      return inArray2.reduce((acc, key, index) => {
        acc[key] = item;
        return acc;
      }, {});
    });
  }
});

keyMap.add({
  args: ['object', 'object'],
  fn: function (inTarget, inObject) {
    return Object.keys(inObject).reduce((acc, key) => {
      acc[inObject[key]] = inTarget[key];
      return acc;
    }, {});
  }
});

const rs1 = keyMap(['a', 'b', 'c']);
const rs2 = keyMap(['a', 'b', 'c'], ['id', 'code', 'key']);
const rs3 = keyMap(
  {
    name: 'afei',
    email: 'afei@js.work'
  },
  {
    name: 'value',
    email: 'label'
  }
);

//... 更多的实现

console.log(rs3);

参考