• js函数的伪重载


    这也是今天写东西是遇到的一个问题,导致我联想起了函数重载的问题。

    在javascript中是没有函数重载机制的,对于用惯了java开发的同学可能就表示吃惊了,我屮艸芔茻,函数

    没有重载?那怎么搞?!!

    从我今天遇到的问题说起吧,还是那个list页面,看过之前刚写的博客的可能知道,我在list页面写了search(order)

    函数来执行查询跳转,但是这个页面很特殊,因为导航栏上面也是有一个搜索功能框的,我将那个功能框的搜索

    函数设定为search(),接下来好玩的事情发生了:

    我从主页面的导航搜索(两个查询参数from和to)进入到结果页(list页面),然后再次点击list页面上面的导航搜索

    这时候,跳转的路径多了好多查询参数,这绝壁是执行了list页面的搜索啊,没有执行导航搜索函数search(),并且

    地址栏上面 order=undefined,这就更加确定是执行了搜索页的搜索函数(因为只有这个函数才会在路径中拼order参

    数),然后一看函数名:一个叫search(order),一个叫search();好像明白了点什么。

    下班回家,写了个页面测试(刚刚写的):

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <div onclick="say('tt');" style="200px;height:200px;border:1px solid;">用户可以看到的</div>
        <script>
        function say(word){
            alert(word);
        };
        function say(){
            alert("hello world");
        };
        </script>
    </body>
    </html>
    
    
        

    点击,弹出“hello world”,函数申明换个顺序亦或是调用函数的时候去除函参,都只会执行最后一个函数名为

    search()的函数,而不会管到底有没有形参,至此可以说明,javascript是没有函数重载的机制的。

    那么这里为什么要说一下js函数的伪重载呢?

     1.通过arguments实现的js函数重载

    function f(){ 
        var len= arguments.length; 
        if(2 == len){ 
            var length = arguments[0]; 
            var width = arguments[1]; 
            f2(length,width); 
        }else{ 
            var length = arguments[0]; 
            f1(length); 
        } 
    } 
    function f1(length){ 
        alert("高为:"+length); 
    } 
    function f2(length,width){ 
        alert("高为:"+length+",宽为:"+width); 
    } 

    代码简单明了,不必多言。

    2.JQuery之父John Resig写的《secrets of the JavaScript ninja》中js重载实现方法

    网上的这个例子有一节代码看半天没看明白,毕竟明天要上班,准备睡觉了,但是!被这个问题困扰着一直睡

    不着,于是爬起来去翻JS高程,一年多之前我还很懵懂的时候看了1/3,现在一些细节性的东西全部忘光了。

    在我的再三思索和测试下,终于把这种重载的实现原理搞懂了!!!贴一下我的理解:

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

    这个函数是为一个对象添加重载方法的。首先来看添加的第一个重载方法(先申明一个对象供后续的重载方法

    操作数据):

    var people = {
      values: ["Dean Edwards", "Alex Russell", "Dean Tom"]
    };

    ①无参数的重载方法

    addMethod(people, "find", function() {
      return this.values;
    });

    我们来看看这个函数的执行过程:

    var old = people["find"];
    people["find"] = function(){
        if(function(){return this.values;}.length === arguments.length){
            return function(){return this.values;}.apply(this,arguments);
        }else if(typeof old === "function"){
            return old.apply(this, arguments);
        }
    }

    ②一个参数的重载方法

    addMethod(people, "find", function(firstName) {
      var ret = [];
      for(var i = 0; i < this.values.length; i++) {
        if(this.values[i].indexOf(firstName) === 0) {
          ret.push(this.values[i]);
        }
      }
      return ret;
    });

    第三个参数的函数体过长,就不全写了

    var old = people["find"];
    people["find"] = function(){
        if(firstName.length === arguments.length){
            return firstName.apply(this,arguments);
        }else if(typeof old === "function"){
            return old.apply(this, arguments);
        }
    }

    ③n个参数的情况,就不介绍了~~

    ④执行的时候

    这里我们分两种情况:执行两个参数的,执行一个参数的;

    其实这里重载方法一直写下来,people的find属性到最后还是只有一个的,就是最后那一个,只不过,不知道你

    注意到没,每次定义重载方法的时候,都会先将原本的方法拿到并赋值给一个变量old,然后在else里返回,注

    意,此处我用了“”这个字眼,个人感觉这个做法实在是太绝妙了,如此嵌套有效地避免了多次定义属性值导致

    的重载方法覆盖的问题。

    按照上面的添加方法顺序,最后的people的find属性应该是这样的(多次添加以此类推):

    people["find"] = function(){
        if(firstName.length === arguments.length){
            return firstName.apply(this,arguments);
        }else if(typeof function(){
                    if(function(){return this.values;}.length === arguments.length){
                        return function(){return this.values;}.apply(this,arguments);
                    }else if(typeof old === "function"){
                        return old.apply(this, arguments);
                    }
                } === "function"){
            return function(){
                    if(function(){return this.values;}.length === arguments.length){
                        return function(){return this.values;}.apply(this,arguments);
                    }else if(typeof old === "function"){
                        return old.apply(this, arguments);
                    }
                }.apply(this, arguments);
        }
    }

    如果执行 people.find("Dean") ,注意这个 arguments.length = 1,和firstName.length(函数支持输入的参数数量,很明显是1)

    相等,于是执行第一个if条件里的内容,将参数 "Dean" 作为firstName函数的函参执行函数,也就是第二个重载方法;

    如果执行 people.find(),注意这个 arguments.length = 0,就进行else的判断,很显然else判断成立,返回

    function(){
            if(function(){return this.values;}.length === arguments.length){
                return function(){return this.values;}.apply(this,arguments);
            }else if(typeof old === "function"){
               return old.apply(this, arguments);
           }
    }.apply(this, arguments);

    该语句将arguments作为参数执行函数,我们继续看这个函数:

    if(function(){return this.values;}.length === arguments.length){
            return function(){return this.values;}.apply(this,arguments);
        }else if(typeof old === "function"){
           return old.apply(this, arguments);
     }

    这个函数又进行一次判断,这次判断,很显然if条件成立(这个arguments是一直贯穿整个过程的),于是最终执行:

    return this.values;

    这个this指向谁?当然是最开始的people咯,于是当无参数时,最终返回people.values!!!

    我认为这种方法处理重载,最大的亮点就是刚才说到的 var old = people["find"];以及将它放在else里面执行!

  • 相关阅读:
    回文字符串问题
    Linux添加nfs共享存储盘
    解读nginx配置
    制作自己的nginx rpm包
    linux编译安装时常见错误解决办法
    redis单机及集群安装
    nginx ssl
    vsftp配置详解
    Linux-文件系统的简单操作
    Linux-Vim编辑器
  • 原文地址:https://www.cnblogs.com/eco-just/p/9545660.html
Copyright © 2020-2023  润新知