当前位置: 首页 > 面试题库 >

如何重载javascript中的函数?

秦琦
2023-03-14
问题内容

经典(非js)重载方法:

function myFunc(){
 //code
}

function myFunc(overloaded){
 //other code
}

Javascript不允许使用同一个名称定义多个功能。这样,这样的事情就会出现:

function myFunc(options){
 if(options["overloaded"]){
  //code
 }
}

除了传递带有重载的对象之外,JavaScript中是否有更好的解决方法来实现函数重载?

传递重载会很快导致函数变得过于冗长,因为每个可能的重载都需要一个条件语句。使用函数来完成//code那些条件语句的内部会导致带有范围的棘手情况。


问题答案:

Javascript中的参数重载有多个方面:

  1. 可变参数 -您可以传递不同的参数集(包括类型和数量),并且该函数的行为将与传递给它的参数相匹配。

  2. 默认参数 -如果未传递参数,则可以为参数定义默认值。

  3. 命名参数 -参数顺序变得无关紧要,您只需命名要传递给函数的参数即可。

以下是有关这些参数处理类别的每个部分。

可变参数

由于javascript没有对参数进行类型检查或需要的参数数量,因此您只需执行一种实现myFunc(),即可通过检查参数的类型,存在或数量来适应传递给它的参数。

jQuery一直在这样做。您可以将某些参数设为可选,也可以根据传递给它的参数在函数中进行分支。

在实现这些类型的重载时,可以使用几种不同的技术:

  1. 您可以通过检查声明的参数名称值是否为来检查是否存在任何给定参数undefined
  2. 您可以使用来检查总数或参数arguments.length
  3. 您可以检查任何给定参数的类型。
  4. 对于可变数量的参数,您可以使用arguments数组访问带有的任何给定参数arguments[i]

这里有些例子:

让我们看一下jQuery的obj.data()方法。它支持四种不同的用法形式:

obj.data("key");
obj.data("key", value);
obj.data();
obj.data(object);

每个触发一个不同的行为,并且不使用这种动态的过载形式,将需要四个单独的功能。

这是一种可以用英语辨别所有这些选项的方法,然后将它们全部合并为代码:

// get the data element associated with a particular key value
obj.data("key");

如果传递给的第一个参数.data()是字符串,第二个参数是undefined,则调用者必须使用此格式。

// set the value associated with a particular key
obj.data("key", value);

如果第二个参数未定义,则设置特定键的值。

// get all keys/values
obj.data();

如果未传递任何参数,则返回返回对象中的所有键/值。

// set all keys/values from the passed in object
obj.data(object);

如果第一个参数的类型是普通对象,则设置该对象的所有键/值。

这是将所有这些组合在一组javascript逻辑中的方法:

 // method declaration for .data()
 data: function(key, value) {
     if (arguments.length === 0) {
         // .data()
         // no args passed, return all keys/values in an object
     } else if (typeof key === "string") {
         // first arg is a string, look at type of second arg
         if (typeof value !== "undefined") {
             // .data("key", value)
             // set the value for a particular key
         } else {
             // .data("key")
             // retrieve a value for a key
         }
     } else if (typeof key === "object") {
         // .data(object)
         // set all key/value pairs from this object
     } else {
         // unsupported arguments passed
     }
 },

该技术的关键是确保要接受的所有形式的参数都是唯一可识别的,并且不会对调用方使用哪种形式造成任何混淆。通常,这要求对参数进行适当的排序,并确保参数的类型和位置具有足够的唯一性,以便您始终可以知道所使用的格式。

例如,如果您的函数带有三个字符串参数:

obj.query("firstArg", "secondArg", "thirdArg");

您可以轻松地使第三个参数为可选,并且可以轻松地检测到该条件,但是您不能仅使第二个参数为可选,因为您无法确定调用方要传递的是哪个参数,因为无法识别第二个参数是否参数是第二个参数,或者省略了第二个参数,所以第二个参数的位置实际上是第三个参数:

obj.query("firstArg", "secondArg");
obj.query("firstArg", "thirdArg");

由于所有三个参数都是同一类型,因此您无法区分不同参数之间的区别,因此您不知道调用者的意图。使用这种调用样式,只有第三个参数可以是可选的。如果您想省略第二个参数,则必须将其作为null(或其他可检测值)传递,并且您的代码将检测到以下内容:

obj.query("firstArg", null, "thirdArg");

这是可选参数的jQuery示例。这两个参数都是可选的,如果未传递,则采用默认值:

clone: function( dataAndEvents, deepDataAndEvents ) {
    dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
    deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;

    return this.map( function () {
        return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
    });
},

这是一个jQuery示例,其中的参数可能会丢失,也可能是三种不同类型中的任何一种都会给您四种不同的重载:

html: function( value ) {
    if ( value === undefined ) {
        return this[0] && this[0].nodeType === 1 ?
            this[0].innerHTML.replace(rinlinejQuery, "") :
            null;

    // See if we can take a shortcut and just use innerHTML
    } else if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
        (jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
        !wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {

        value = value.replace(rxhtmlTag, "<$1></$2>");

        try {
            for ( var i = 0, l = this.length; i < l; i++ ) {
                // Remove element nodes and prevent memory leaks
                if ( this[i].nodeType === 1 ) {
                    jQuery.cleanData( this[i].getElementsByTagName("*") );
                    this[i].innerHTML = value;
                }
            }

        // If using innerHTML throws an exception, use the fallback method
        } catch(e) {
            this.empty().append( value );
        }

    } else if ( jQuery.isFunction( value ) ) {
        this.each(function(i){
            var self = jQuery( this );

            self.html( value.call(this, i, self.html()) );
        });

    } else {
        this.empty().append( value );
    }

    return this;
},

命名参数

其他语言(例如Python)允许人传递命名参数,以作为仅传递某些参数并使参数独立于其传递顺序的一种方式。Javascript不直接支持命名参数的功能。通常使用的设计模式是传递属性/值的映射。这可以通过传递具有属性和值的对象来完成,或者在ES6及更高版本中,您实际上可以传递Map对象本身。

这是一个简单的ES5示例:

jQuery
$.ajax()接受一种用法,您只需向其传递一个参数即可,该参数是具有属性和值的常规Javascript对象。您传递给它的哪些属性确定哪些参数/选项将传递给ajax调用。一些可能是必需的,许多是可选的。由于它们是对象的属性,因此没有特定的顺序。实际上,可以在该对象上传递30多种不同的属性,只需要一个(URL)。

这是一个例子:

$.ajax({url: "http://www.example.com/somepath", data: myArgs, dataType: "json"}).then(function(result) {
    // process result here
});

$.ajax()然后,在实现内部,它可以查询传入对象上传递了哪些属性,并将这些属性用作命名参数。这可以通过使用for (prop in obj)或通过将所有属性放入一个数组中Object.keys(obj),然后对该数组进行迭代来完成。

当有大量参数和/或许多参数是可选参数时,此技术在Javascript中非常常用。注意:这为实现函数增加了责任,以确保存在最小的有效参数集,并为调用者提供一些调试反馈,如果传递的参数不足(可能是通过抛出异常并附带有用的错误消息),则缺少什么。

在ES6环境中,可以使用解构为上述传递的对象创建默认属性/值。

这是该文章的一个示例:

function selectEntries({ start=0, end=-1, step=1 } = {}) {
    ···
};

这将创建默认属性和值startendstep传递到一个对象的属性selectEntries()的功能。

函数参数的默认值

在ES6中,Javascript为参数的默认值添加了内置语言支持。

例如:

function multiply(a, b = 1) {
  return a*b;
}

multiply(5); // 5


 类似资料:
  • 问题内容: 用JavaScript伪造函数重载的最佳方法是什么? 我知道不可能像其他语言一样重载Javascript中的函数。如果我需要一个函数有两个用途和这是最好的/优选的方法: 首先使用不同的名称 使用类似的可选参数 使用参数数量 检查参数类型 或如何? 问题答案: 使用参数进行函数重载的最佳方法是不检查参数长度或类型;检查类型只会使您的代码变慢,并且您可以享受数组,空值,对象等的乐趣。 大多

  • 实际代码中 funa 里有其他代码,拼数据一起 ajax 请求类的,上面只是简化代码 func 会调用 funa 并且有其他调用 https://www.typescriptlang.org/zh/play?#code/GYVwdgxgLglg9mABKMBDRAKARgLgM5QBOMYA5gJQ5ggC2WApoQFArTxIrrb5EmkDaAXUrU6jIS3BsEycF1wFiZAD6K

  • 问题内容: 覆盖和过载之间有什么区别? 问题答案: 重载:在编译时根据指定参数的数量和类型选择方法 签名 覆盖:在执行时根据目标对象的实际类型(与表达式的编译时类型相对)选择方法 实现 例如: 这两个调用都是 重载的 示例。有两种方法,称为,编译器确定要调用的签名。 第一次调用是 覆盖 的示例。编译器选择签名“ foo(int)”,但是在执行时,目标对象的类型确定要使用的实现应为in中的一个。

  • 我有这个界面: 我需要一个类来实现它,但我无法获得在类中实现getDist()方法的正确语法。。 它说: 类'Point'声明接口'IPoint'但不实现它:类型'Point'和'IPoint'的属性'getDist'的类型不兼容:调用类型'()= 做这件事的正确方法是什么? 谢谢

  • 本文向大家介绍JavaScript重载函数实例剖析,包括了JavaScript重载函数实例剖析的使用技巧和注意事项,需要的朋友参考一下 1.javascript 中是没有重载函数这个概念的! 首先javascript是没有重载函数这个概念的,很久以前,我用javascript做网页的时候,写一些简单的效果,根本不需要用到重载函数,当写游戏的时候,有大量的函数的时候,就想用重载函数了,没想到java

  • 问题内容: 在PHP中,函数重载和函数覆盖是什么意思。两者之间有什么区别?无法弄清楚它们之间有什么区别。 问题答案: 重载 定义的函数具有相似的签名,但具有不同的参数。 覆盖 仅与派生类相关,派生类中的父类已定义了一个方法,而派生类希望 覆盖 该方法。 在PHP中,您只能使用magic方法重载方法。 覆盖 的示例: