如何在javascript中重载函数? [英] How to overload functions in javascript?

查看:71
本文介绍了如何在javascript中重载函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

经典(非js)重载方法:

Classical (non-js) approach to overloading:

function myFunc(){
 //code
}

function myFunc(overloaded){
 //other code
}

Javascript不允许使用相同的名称定义多个函数。因此,这样的事情会显示出来:

Javascript wont let more than one function be defined with the same name. As such, things like this show up:

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

是除了传递带有重载的对象之外,还有更好的javascript函数重载方法吗?

Is there a better workaround for function overloading in javascript other than passing an object with the overloads in it?

传递重载会很快导致函数变得过于冗长因为每个都可能然后,重载需要一个条件语句。使用函数在这些条件语句中完成 // code 会导致范围很棘手。

Passing in overloads can quickly cause a function to become too verbose because each possible overload would then need a conditional statement. Using functions to accomplish the //code inside of those conditional statements can cause tricky situations with scopes.

推荐答案

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

There are multiple aspects to argument overloading in Javascript:


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

  1. Variable arguments - You can pass different sets of arguments (in both type and quantity) and the function will behave in a way that matches the arguments passed to it.

默认参数 - 如果参数未通过,您可以定义参数的默认值。

Default arguments - You can define a default value for an argument if it is not passed.

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

Named arguments - Argument order becomes irrelevant and you just name which arguments you want to pass to the function.

下面是关于每个参数处理类别的一个部分。

Below is a section on each of these categories of argument handling.

因为javascript没有类型检查关于参数或所需的参数数量,你可以只有一个 myFunc()的实现,它可以通过检查参数的类型,存在或数量来适应传递给它的参数。

Because javascript has no type checking on arguments or required qty of arguments, you can just have one implementation of myFunc() that can adapt to what arguments were passed to it by checking the type, presence or quantity of arguments.

jQuery一直这样做。你可以使一些参数成为可选参数,或者你可以根据传递给它的参数在你的函数中进行分支。

jQuery does this all the time. You can make some of the arguments optional or you can branch in your function depending upon what arguments are passed to it.

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

In implementing these types of overloads, you have several different techniques you can use:


  1. 您可以通过检查声明的参数名称值是否<$来检查是否存在任何给定的参数c $ c> undefined 。

  2. 您可以使用 arguments.length 检查总数量或参数。

  3. 您可以检查任何给定参数的类型。

  4. 对于可变数量的参数,您可以使用参数使用 arguments [i] 访问任何给定参数的伪数组。

  1. You can check for the presence of any given argument by checking to see if the declared argument name value is undefined.
  2. You can check the total quantity or arguments with arguments.length.
  3. You can check the type of any given argument.
  4. For variable numbers of arguments, you can use the arguments pseudo-array to access any given argument with arguments[i].

以下是一些例子:

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

Let's look at jQuery's obj.data() method. It supports four different forms of usage:

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

每一个都触发不同的行为,如果不使用这种动态形式的重载,则需要四个独立的功能。

Each one triggers a different behavior and, without using this dynamic form of overloading, would require four separate functions.

以下是用英语辨别所有这些选项的方法,然后我将它们全部用代码组合:

Here's how one can discern between all these options in English and then I'll combine them all in code:

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

如果第一个参数传递给 .data()是一个字符串,第二个参数是 undefined ,然后调用者必须使用此表单。

If the first argument passed to .data() is a string and the second argument is undefined, then the caller must be using this form.

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

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

If the second argument is not undefined, then set the value of a particular key.

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

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

If no arguments are passed, then return all keys/values in a returned object.

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

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

If the type of the first argument is a plain object, then set all keys/values from that object.

以下是如何在一组javascript逻辑中组合所有这些:

Here's how you could combine all of those in one set of javascript logic:

 // 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
     }
 },



< hr>

这种技术的关键是确保您想要接受的所有形式的参数都是唯一可识别的,并且从不会混淆调用者使用哪种形式。这通常需要对参数进行适当排序,并确保参数的类型和位置有足够的唯一性,您可以随时告诉使用哪种形式。


The key to this technique is to make sure that all forms of arguments you want to accept are uniquely identifiable and there is never any confusion about which form the caller is using. This generally requires ordering the arguments appropriately and making sure that there is enough uniqueness in the type and position of the arguments that you can always tell which form is being used.

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

For example, if you have a function that takes three string arguments:

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

您可以轻松地将第三个参数设为可选,您可以轻松检测到该条件,但不能只做第二个参数是可选的,因为你无法分辨调用者的哪一个意味着传递,因为没有办法确定第二个参数是第二个参数还是第二个参数被省略所以第二个参数的位置是什么实际上是第三个参数:

You can easily make the third argument optional and you can easily detect that condition, but you cannot make only the second argument optional because you can't tell which of these the caller means to be passing because there is no way to identify if the second argument is meant to be the second argument or the second argument was omitted so what's in the second argument's spot is actually the third argument:

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

因为所有三个参数都是相同的类型,所以你不能区分不同的参数,所以你不知道打电话的意图。使用此调用样式,只有第三个参数可以是可选的。如果你想省略第二个参数,它必须作为 null (或其他一些可检测的值)传递,而你的代码会检测到:

Since all three arguments are the same type, you can't tell the difference between different arguments so you don't know what the caller intended. With this calling style, only the third argument can be optional. If you wanted to omit the second argument, it would have to be passed as null (or some other detectable value) instead and your code would detect that:

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






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


Here's a jQuery example of optional arguments. both arguments are optional and take on default values if not passed:

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示例,其中参数可能丢失或三个中的任何一个不同的类型,它给你四个不同的重载:

Here's a jQuery example where the argument can be missing or any one of three different types which gives you four different overloads:

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对象。


Named Arguments

Other languages (like Python) allow one to pass named arguments as a means of passing only some arguments and making the arguments independent of the order they are passed in. Javascript does not directly support the feature of named arguments. A design pattern that is commonly used in its place is to pass a map of properties/values. This can be done by passing an object with properties and values or in ES6 and above, you could actually pass a Map object itself.

这是一个简单的ES5示例:

Here's a simple ES5 example:

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

jQuery's $.ajax() accepts a form of usage where you just pass it a single parameter which is a regular Javascript object with properties and values. Which properties you pass it determine which arguments/options are being passed to the ajax call. Some may be required, many are optional. Since they are properties on an object, there is no specific order. In fact, there are more than 30 different properties that can be passed on that object, only one (the url) is required.

这是一个例子:

$.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)然后迭代该数组。

Inside of the $.ajax() implementation, it can then just interrogate which properties were passed on the incoming object and use those as named arguments. This can be done either with for (prop in obj) or by getting all the properties into an array with Object.keys(obj) and then iterating that array.

当有大量参数和/或许多参数是可选的时,这种技术在Javascript中非常常用。注意:这会对实现函数负责,以确保存在最小有效参数集,并为调用者提供一些调试反馈,如果传递的参数不足则会丢失哪些内容(可能通过抛出有用错误消息的异常) 。

This technique is used very commonly in Javascript when there are large numbers of arguments and/or many arguments are optional. Note: this puts an onus on the implementating function to make sure that a minimal valid set of arguments is present and to give the caller some debug feedback what is missing if insufficient arguments are passed (probably by throwing an exception with a helpful error message).

在ES6环境中,可以使用解构来为上面传递的对象创建默认属性/值。这在此参考文章中有更详细的讨论。

In an ES6 environment, it is possible to use destructuring to create default properties/values for the above passed object. This is discussed in more detail in this reference article.

以下是该文章的一个例子:

Here's one example from that article:

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

这会为 start ,结束步骤传递给 selectEntries()的对象的属性 function。

This creates default properties and values for the start, end and step properties on an object passed to the selectEntries() function.

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

In ES6, Javascript adds built-in language support for default values for arguments.

例如:

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

multiply(5); // 5

进一步说明如何使用这里是MDN

这篇关于如何在javascript中重载函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆