所谓重载,就是一组相同的函数名,有不同个数的参数,在使用时调用一个函数名,传入不同参数,根据你的参数个数,来决定使用不同的函数!但是我们知道js中是没有重载的,因为后定义的函数会覆盖前面的同名函数,但是我们又想实现函数重载该怎么办呢?

第一种方法:

  这种方法比较简单,给一个思路,大家肯定都能理解,就是函数内部用switch语句,根据传入参数的个数调用不同的case语句,从而功能上达到重载的效果。

  这种方法简单粗暴。但是对于一个正在学习js的人来说,这种方法未免太敷衍了。

  下面重点介绍一下第二种,老实说我看的时候很吃力看了一个小时才捋清楚,因为有的知识点虽然看过了但是不熟悉。这次就给我上了一课,教会了我很多东西。

第二种方法:

  我们这个例子,是如果你不传入参数,就会输出所有的人,输入firstname,就会输出匹配的人,如果输入全名的人,也会输出匹配的人。如果用重载的话,用户体验确实会很好(这个例子是我学习时从网上扒下来的,很有代表性,但是他们都没有写实现过程,我来和大家谈论一下实在的东西)

     function method(obj,name,fnc){
var old = obj[name];
console.log(old instanceof Function);
obj[name] = function(){
console.log(arguments.length+" "+fnc.length);
if(arguments.length === fnc.length){
return fnc.apply(this,arguments);
}else if(typeof old === "function"){
return old.apply(this,arguments);
}
}
}
var people = {
values:["Zhang san","Li si"]
};
method(people,"find",function(){
console.log("无参数");
return this.values;
})
method(people,"find",function(firstname){
console.log("一个参数");
var ret = [];
for(var i = ;i < this.values.length;i++){
if(this.values[i].indexOf(firstname) === ){
ret.push(this.values[i])
}
}
return ret;
})
method(people,"find",function(firstname,lastname){
console.log("两个参数");
var ret = [];
for(var i = ;i < this.values.length;i++){
if(this.values[i] == firstname + " " + lastname){
ret.push(this.values[i])
}
}
return ret;
})
console.log(people.find());
console.log(people.find("Zhang"));

思路:这段代码第一眼看到我是懵逼的,再看有点思路,再看又懵了。这种方法巧妙的运用了闭包原理,既然js后面的函数会覆盖前面的同名函数,我就强行让所有的函数都留在内存里,等我需要的时候再去找它。有了这个想法,是不是就想到了闭包,函数外访问函数内的变量,从而使函数留在内存中不被删除。就是闭包。

实现过程:我们看一下上面这段代码,最重要的是method方法的定义:这个方法中最重要的一点就是这个old,这个old真的很巧妙。它的作用相当于一个指针,指向上一次被调用的method函数,这样说可能有点不太懂,我们根据代码来说,js的解析顺序从上到下为。

  1.解析method(先不管里面的东西)

  2.method(people,"find",function()  执行这句的时候,它就回去执行上面定义的方法,然后此时old的值为空,因为你还没有定义过这个函数,所以它此时是undefined,然后继续执行,这是我们才定义 obj[name] = function(),然后js解析的时候发现返回了fnc函数,更重要的是fnc函数里面还调用了method里面的变量,这不就是闭包了,因为fnc函数的实现是在调用时候才会去实现,所以js就想,这我执行完也不能删除啊,要不外面那个用啥,就留着吧先(此处用call函数改变了fnc函数内部的this指向)

  3.好了第一次method的使用结束了,开始了第二句,method(people,"find",function(firstname) 然后这次使用的时候,又要执行old = obj[name]此时的old是什么,是函数了,因为上一条语句定义过了,而且没有删除,那我这次的old实际上指向的是上次定义的方法,它起的作用好像一个指针,指向了上一次定义的 obj[name]。然后继续往下解析,又是闭包,还得留着。

  4.第三此的method调用开始了,同理old指向的是上次定义的 obj[name] 同样也还是闭包,还得留着。

  5.到这里,内存中实际上有三个 obj[name],因为三次method的内存都没有删除,这是不是实现了三个函数共存,同时还可以用old将它们联系起来是不是很巧妙

  6.我们 people.find() 的时候,就会最先调用最后一次调用method时定义的function,如果参数个数相同 也就是  arguments.length === fnc.length 那么就执行就好了,也不用找别的函数了,如果不相同的话,那就得用到old了  return old.apply(this,arguments); old指向的是上次method调用时定义的函数,所以我们就去上一次的找,如果找到了,继续执行 arguments.length === fnc.length  如果找不到,再次调用old 继续向上找,只要你定义过,肯定能找到的,对吧!

  总结:运用闭包的原理使三个函数共存于内存中,old相当于一个指针,指向上一次定义的function,每次调用的时候,决定是否需要寻找。

执行过程很容易说明这一点:首先第一次调用的时候 old肯定不是函数,所以instance判断是false,继续调用的话就会为true。然后,我们调用method的顺序,是从没有参数到两个参数,所以我们最先调用find方法,是最后一次method调用时定义的,所以fnc的length长度是2.然后向上找,length为1,最后终于找到了length为0的然后执行,输出。

原创学习博客,欢迎讨论,指出不足之处。

js如何实现重载的更多相关文章

  1. JavaScript基础12——js的方法重载

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  2. 实现js中的重载

    重载是面向对象语言里很重要的一个特性,JS中没有真正的重载,是模拟出来的(因为js是基于对象的编程语言,不是纯面向对象的,它没有真正的多态:如继承.重载.重写) 一.什么时候用重载? 举例: func ...

  3. 妙用缓存调用链实现JS方法的重载

    来自于我的博客http://sweets.cf/,转载注明出处 1.什么是方法重载 方法重载是指在一个类中定义多个同名的方法,但要求每个方法具有不同的参数的类型或参数的个数. 简而言之就是:方法重载就 ...

  4. js没有函数重载

    上面这道题,要求判断输出的y和z分别为什么 一开始,我选择了2,4 后来发现答案是4,4 意识到js中没有函数重载!!!即使声明了两个同名函数,结果也是后面的函数覆盖了前一个函数. 而且函数声明会提升 ...

  5. 如何实现JS函数的重载

    javascript不能支持函数的重载,如下: function f(length) { alert("高为:"+length); } function f(length,widt ...

  6. 关于js 重载

    拜读js忍者修炼一书 读到关于js函数重载内容这个模块 主要是介绍通过js的访问argument这个参数来实现js函数的重载 通过在函数内部进行判断js argument参数的长度 代码如下所示 va ...

  7. Js函数function基础理解

    正文:我们知道,在js中,函数实际上是一个对象,每个函数都是Function类型的实例,并且都与其他引用类型一样具有属性和方法.因此,函数名实际上是指向函数对象的指针,不与某个函数绑定.在常见的两种定 ...

  8. JS 笔记(二) - 函数

    1. 函数的 声明 1) 声明式写法 function j1(id){ alert(id); } 2) 声明匿名函数变量 var j2 = function (a, b) { alert(a + &q ...

  9. JS语法(二)

    JS变量 var 变量名 = 变量值://自己会判断什么类型 一个好的编程习惯是,在代码开始处,统一对需要的变量进行声明. var name = “xiaosan”, age = 22, addres ...

随机推荐

  1. 为什么vue支持IE9以上的IE浏览器?

    原因如下: 1.vue框架中核心的双向绑定原理是利用Object.defineProperty()方法实现的. 2.该方法第一个被实现是在IE8中,但是存在诸多限制:只能在DOM对象上使用这个方法,而 ...

  2. CentOS安装MySQL的完整步骤

    1.官方安装文档 http://dev.mysql.com/doc/mysql-yum-repo-quick-guide/en/ 2.下载 Mysql yum包 http://dev.mysql.co ...

  3. python-web自动化-文件上传操作(非input标签的上传,需要借助第三方工具)

    文件上传操作 一.文件上传分两种情况:1. 如果是input可以直接输入路径的,可以直接调send_keys输入路径 2. 非input标签的上传,需要借助第三方工具:    2.1 Autolt 需 ...

  4. 七层协议&网络配置

    1.输入CMD 2.ipconfig-all 可查看详细的电脑网络配置,子网掩码(subnet mask)又叫网络掩码.地址掩码.子网络遮罩,它是一种用来指明一个IP地址的哪些位标识的是主机所在的子网 ...

  5. html 文本解码 xpath 获取html标签

    import htmlimport etree selector = etree.HTML(res) url_h2 = selector.xpath("//a[@_stat='video:p ...

  6. windows开发各种dll缺失

    推荐使用 depend这个工具,非常好用 http://www.dependencywalker.com/ 打开对应的文件,就能看到缺失了哪些dll 感谢博主: https://blog.csdn.n ...

  7. 【Python】itchat

    错误:http://bbs.51cto.com/thread-1501477-1.html 解决方法降低certifi版本 >>> import itchat >>> ...

  8. 关于UILabel产生黑边的原因及去除方法

    原因:因为label自适应宽度得出来的labelsize.width是小数,才会有黑边 去除方法: 将labelsize.width转换成整数,如下: CGSize size = CGSizeMake ...

  9. leetcode每日刷题计划-简单篇day11

    Num 121 买卖股票的最佳时期 Best Time to Buy and Sell Stock class Solution { public: int maxProfit(vector<i ...

  10. Springboot admin 发送邮件失败:com.sun.mail.smtp.SMTPSenderFailedException: 553 Mail from must equal authorized user

    发邮件已经是老生常谈了,今天又遇到了,而且又出了各种问题.我晕哦. 我的配置是: spring.mail.host=smtp..com spring.mail.username=klxxxx spri ...