谈一个用闭包实现的重载

闭包是js的特性,也是区分其他语言的关键特点之一。

偶然浏览博客,看到一个据说是 jQuery 某个版本实现函数重载的一个方法,出自 jQuery 作者 John Resig:

function addMethod(object, name, f) {
    var old = object[name];
    object[name] = function() {
        if (f.length === arguments.length) {
            return f.apply(this, arguments);
        } else if (typeof old === "function") {
            return old.apply(this, arguments);
        }
    };
}

下面的代码可以展示其重载的实现效果:

const Obj = {};
const f1 = () => {
    console.log("no prm");
};
const f2 = (x) => {
    console.log("one prm", x);
};
const f3 = (x, y) => {
    console.log("two prms", x, y);
};
addMethod(Obj, "find", f1);
addMethod(Obj, "find", f2);
addMethod(Obj, "find", f3);
Obj.find()

个人觉得这种用闭包的方式存在很大的问题,通过 old 串联三个闭包,导致的结果就是最先重载的方法需要跨越多个闭包实现,可以通过打印直观的看出来;

function addMethod(object, name, f) {
    var old = object[name];
    object[name] = function() {
        console.log("span")
        if (f.length === arguments.length) {
            return f.apply(this, arguments);
        } else if (typeof old === "function") {
            return old.apply(this, arguments);
        }
    };
}
// span span span no prm

第一个无参函数的执行跨越了两层作用域,可见这种方式虽然节省了变量,但是一方面让代码可读性变得晦涩,另一方面使用了闭包的缺点,而非优点,我会使用下面的方式实现:

const addMethod = (obj, type, f) => {
    obj[f.length] = f;
    obj[type] = (...args) => {
        console.log("span");
        return obj[args.length](...args);
    };
};
Obj.find(); // span no prm

这样任何重载方法的执行都不需要跨作用域去查找,可能有人觉得为什么要在对象挂载一些无关的参数,这样太草率了,没有章法。这里也只是为了说明同样的重载可以有更好的选择,本身重载的方法就不是非得挂到对象上,单独实现反而利于函数式编程。

posted on 2020-05-14 23:50  Lowki  阅读(151)  评论(0编辑  收藏  举报