首页 > 编程语言 >详解如何通过JavaScript实现函数重载

详解如何通过JavaScript实现函数重载

时间:2023-10-10 16:13:25浏览次数:42  
标签:searcher 调用 函数 JavaScript 查询 详解 重载 find log

有的同学在开发中可能遇到过一个困扰,但是很少有人去解决这个问题,我这用一个例子展现出来

const searcher = {};
searcher.findAll = () => {
  console.log("查询所有用户");
};
searcher.findByName = (name) => {
  console.log("按照用户名称查询");
};
searcher.findByFirstNameAndLastName = (firstName, lastName) => {
  console.log("按照姓和名用户查询");
};

可以看到上方的searcher对象有三个方法,但是他的查询逻辑是不一样。 findAll查询所有用户;findByName按照用户名查;findByFirstNameAndLastName是按照姓和名查询用户,结构上没任何问题,那问题在哪?,恶心因为都是在做查询,但又不得不给每一个函数取不同的名字,因为一旦重名就覆盖了,如果说他们能取一样的名字那该有多好

searcher.find = () => {
  console.log("查询所有用户");
};
searcher.find = (name) => {
  console.log("按照用户名称查询");
};
searcher.find = (firstName, lastName) => {
  console.log("按照姓和名用户查询");
};

不传参数就是查所有用户

searcher.find()

给一个参数就是按照用户名来查询

searcher.find("aa")

给两个参数就是按照用户的姓跟名来查询

searcher.find("aa", "bb")

到用得时候也是非常的简单,也符合逻逻辑,这个就叫做函数重载

函数重载:就是给函数取同一样的一个函数名,根据你传递不同的参数数量,分别去调用不同的函数

好处:就在于使用不同的逻辑产生的函数,给他们取一个相同的名字,这样在使用上我只需要记住这个一样的名字就可以了,而不用去记这三个不同的名字,他有效的降低调用函数时产生的心智负担。

 但是JS不支持函数重载,所以说如果你写成已上的形式,无论你怎么调用,一定是调用最后一个函数,因为最后一个函数把前面的全部覆盖了
不传参数试一下,你看永远都是走最后一个函数的log。

    searcher.find() // 按照姓和名用户查询

那有什么办法呢?在很早的时候jQuery之父John Resig 他就已经提出了一个想法,我们能不能实现一个方法来帮助我们在js中完成函数重载?

于是他想出了一个addMethod方法,就是当我要重载的时,我不直接去定义函数,因为直接定义函数就会出现一个永远只调用最后一个函数的问题,而调用addMethod来定义函数,把对象传进去,把函数的名字传进去,把函数的实现传进去,后面依次同理

addMethod(searcher, 'find', () => {
    console.log('查询所有用户')
})
addMethod(searcher, 'find', (name) => {
    console.log('按照用户名称查询')
})
addMethod(searcher, 'find', (firstName, lastName) => {
    console.log('按照姓和名用户查询')
})

写成这种格式之后,后面调用searcher.find()就能够完成函数重载,问题是这个方法我们得要自己实现,那么如何来实现? 这个方法他接受三个参数,如果你不加处理的话你可能写成下面函数一样,给对象加一个属性,这个属性等于一个函数,调用这个函数实际上就是在运行定义的实现函数fn,把this绑定带过去 然后把传递过来的arguments带过去

function addMethod(object, name, fn) {
  object[name] = function () {
      fn.apply(this, arguments)
  }
}

仅仅这么些还是搞不定,因为每次调用addMethod最后一次调用一定会把object里面同一个属性给覆盖掉,那么如何处理?看下方代码

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

首先我不传参数走查询所有用户,传一个参数走按照用户名查询,传两个参数按照姓和名查询

 

直接看方法体有的同学可能不理解其中的巧妙,我来研究一下这个方法并记录一下执行规则

第一次调用: 通过 old 变量首先保存了之前成员的值,当然这一次保存由于是第一次调用,所以他是一个undefined 然后给object[name]赋值了一个新的函数,这个函数在运行的时候做了一个判断,当你传递的实参数量与你定义函数形参数量一致的时候就执行该函数由此可得:

 第二次调用:关键是否则,判断一下old是否是函数,如果是那调用old就会执行上面第一次得出的逻辑,同理可得:

 第三次调用:同理可得:

 以上是一个注册的顺序,当我们调用时传递0个参数,他会从最后一个开始执行,当形参数量相等就会直接执行当前的方法,如果不相等就会执行old也就是上一个find的逻辑,类似于冒泡执行,等到执行到第一次注册的逻辑判断时形参数量相等了,就直接执行第一次注册的方法,执行打印 "查询所有用户"

searcher.find() // 查询所有用户

总结

其实就是用到了闭包,将闭包形成了闭包链把我们传递的方法依次注册。在调用的时候从最后一个有序的去找,用这种非常巧妙的方式,用极少的代码就实现了一个函数重载的效果,函数重载虽然说你不一定能用到,但是通过去解析这个addMethod,我们可以感受到有这么智慧的实现方案,肯定对你将来实现某一些东西的时候,有所启发。

标签:searcher,调用,函数,JavaScript,查询,详解,重载,find,log
From: https://www.cnblogs.com/caihongmin/p/17754929.html

相关文章

  • 前端面试八股文 JavaScript
    前端面试八股文JavaScript谈谈对原型链的理解在JavaScript中,每个对象都有一个原型对象proto,指向其构造函数的原型对象prototype。当我们创建一个新的实例对象时,这个对象会从其构造函数的原型对象prototype中继承属性和方法。如果实例对象自身没有某个属性或方法,但是其构造函数......
  • C++11之类型转换(2千字长文详解)
    C++11之类型转换C语言中的类型转换在C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与接收返回值类型不一致时,就需要发生类型转化,C语言中总共有两种形式的类型转换:隐式类型转换和显式类型转换。隐式类型转化:编译器在编译阶段自动进行,能转就......
  • Go通道机制与应用详解
    本文深入探讨了Go语言中通道(Channel)的各个方面,从基础概念到高级应用。文章详细解析了通道的类型、操作方法以及垃圾回收机制,更进一步通过具体代码示例展示了通道在数据流处理、任务调度和状态监控等多个实际应用场景中的作用。本文旨在为读者提供一个全面而深入的理解,以更有效地......
  • JavaScript 浮点数运算的精度问题
    来源:https://zhuanlan.zhihu.com/p/191395766问题描述在JavaScript中整数和浮点数都属于 Number 数据类型,所有数字都是以64位浮点数形式储存,即便整数也是如此。所以我们在打印 1.00 这样的浮点数的结果是 1 而非 1.00 。在一些特殊的数值表示中,例如金额,这样看上去......
  • C# DataTable使用方法详解
    在项目中常常常使用到DataTable,假设DataTable使用得当,不仅能使程序简洁有用,并且可以提高性能,达到事半功倍的效果,现对DataTable的使用技巧进行一下总结。1、添加引用1using System.Data;2、创建表1234//创建一个空表DataTabledt=n......
  • JavaScript
    1可以在任何位置,一般在body后<script>window.alert("JS");//浏览器弹出警告框document.write("HelloJS");//写入html页面中console.log("hellojs")//控制台输出vara=20;//声明全局变量var......
  • 在JavaScript比较中,应该使用哪个等号运算符(== vs ===)?
    内容来自DOC[https://q.houxu6.top/?s=在JavaScript比较中,应该使用哪个等号运算符(==vs=)?](https://q.houxu6.top/?s=在JavaScript比较中,应该使用哪个等号运算符(vs===)?)我正在使用JSLint来检查JavaScript代码,并且它返回了许多建议,建议在if语句中比较idSele_UNVEHtype.value.......
  • 在JavaScript中遍历数组的循环(对于每个)
    内容来自DOChttps://q.houxu6.top/?s=在JavaScript中遍历数组的循环(对于每个)我可以使用JavaScript遍历数组中的所有条目吗?TL;DR你最好选择通常的方法是:使用for-of循环(ES2015+只支持;规范|MDN)-简单且适用于async。for(constelementoftheArray){//.......
  • TypeScript与JavaScript比较(区别)
     TypeScript和JavaScript是目前项目开发中较为流行的两种脚本语言,TypeScript是JavaScript的一个超集,但是TypeScript与JavaScript之间又有什么样的区别呢?在选择开发语言时,又该如何抉择呢?本文将会深入对比这两种语言,讨论两种语言之间的关联和差异,并概述两种语言各自的优势......
  • Clickhouse时间日期函数一文详解+代码展示
    转:https://blog.csdn.net/master_hunter/article/details/125762575一、时间函数和MySQL时间函数有些不同,但是时间函数的功能是一样的,这里把常用的时间函数给出,效果以实际代码运行结果为准: 1.取当前时间SELECT now()AStimeSELECT today()AStime获取当前时间戳SELECT ......