instructions

There is no real function overloading in JavaScript.

Function overloading

The function name is the same, but the parameter list (including the parameter number and parameter type) is different. You can perform different operations based on the parameters.

Let’s take an example

function overload(a){
	console.log('One parameter')}function overload(a,b){
	console.log('Two arguments')}// In programming languages that support overloading, such as Java
overload(1);   	  // A parameter
overload(1.2);    // Two parameters


/ / in JavaScript
overload(1);   	  // Two parameters
overload(1.2);    // Two parameters
Copy the code

In JavaScript, two functions with the same name appear in the same scope, and the latter one overwrites the previous one, so there is no real overloading of JavaScript.

But there are various ways to simulate the effects of overloading in JavaScript.

Let’s look at the first option, passThe arguments objectTo implement the

The arguments object is an array object inside a function that holds all the arguments passed to the function when the function is called.

function overload () {
  if (arguments.length === 1) {
    console.log('One parameter')}if (arguments.length === 2) {
    console.log('Two arguments')
  }
}

overload(1);      // A parameter
overload(1.2);  // Two parameters
Copy the code

This example is very simple, which is to determine how many arguments there are by judging the length property of the Arguments object, and then what to do.

But in the case of fewer parameters, it’s ok, if there are more parameters, you need to write a lot of if judgment, which is a problem.

So, let’s look at a classic example before we look at this example, let’s look at a requirement, we have a Users object, and the Users object has some names in its values property. A name consists of two parts, first-name to the left of the space and last-name to the right of the space, as follows.

var users = {
  values: ["Dean Edwards"."Alex Russell"."Dean Tom"]};Copy the code

We’re going to add a find method to the Users object,

When no arguments are passed, the entire users.values is returned; When a parameter is passed, the element whose first-name matches the parameter is returned. If two parameters are passed, both first-name and last-name are returned.

The find method in this requirement needs to perform different operations depending on the number of arguments. Next we add the find method to the Users object by using an addMethod function.

function addMethod (object, name, fn) {
  // Save the old object[name] method in old
  var old = object[name];

  // Redefine the object[name] method
  object[name] = function () {
    // If the function needs the same number of arguments as it actually passed, it calls fn directly
    if (fn.length === arguments.length) {
      return fn.apply(this.arguments);

      // If not, check whether old is a function.
      // If so, call old, which is the object[name] method saved earlier
    } else if (typeof old === "function") {
      return old.apply(this.arguments); }}}Copy the code

The addMethod function, which takes three arguments: the object to which the method is bound, the name of the method to bind, and the method to bind

The addMethod function uses the length attribute as well as the arguments object to determine the number of arguments.

The length property of the function, which returns the number of parameters defined by the function.

Arguments. length is the number of arguments that a function needs, and arguments.length is the number of arguments that a function is actually given when called

function fn (a, b) {
  console.log(arguments.length)
}
console.log(fn.length);  / / 2
fn('a');	/ / 1
Copy the code

So let’s go ahead and use this addMethod function

// When no arguments are passed, the entire values array is returned
function find0 () {
  return this.values;
}
// When passing an argument, return the array element matched by firstName
function find1 (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;
}
// When passing two arguments, return an array element matching both firstName and lastName
function find2 (firstName, lastName) {
  var ret = [];
  for (var i = 0; i < this.values.length; i++) {
    if (this.values[i
    ] === (firstName + "" + lastName)) {
      ret.push(this.values[i ]); }}return ret;
}
// Add methods to the Users object that handle no arguments
addMethod(users, "find", find0);

// Add a method to the Users object to handle a parameter
addMethod(users, "find", find1);

// Add methods to the Users object to handle two parameters
addMethod(users, "find", find2);

/ / test:
console.log(users.find()); //["Dean Edwards", "Alex Russell", "Dean Tom"]
console.log(users.find("Dean")); //["Dean Edwards", "Dean Tom"]
console.log(users.find("Dean"."Edwards")); //["Dean Edwards"]
Copy the code

The addMethod function takes advantage of closures by concatenating each function with the old variable, leaving all functions in memory.

Each time addMethod is called, an old is generated, forming a closure. We can print the find method to the console using console.dir(users.find).

The example above was written by John Resig, the father of jQuery, on his blog and in the first edition of his book Secrets of the JavaScript Ninja, In chapter 4 of the book, Function overloading is also explained. The addMethod Function in the article is example 4.15 in the book. If you are interested, you can check it out.

All of the above examples are essentially determining the number of parameters and performing different operations depending on the number of parameters, whereas the next example is performing different operations based on the type of parameters.

Let’s look at jQueryCSS () method.

The CSS () method returns or sets one or more style attributes for the matched element.

css(name|pro|[,val|fn])

We can see that the CSS () method has five parameter cases, three of which have one parameter and two of which have two parameters. In the case of a single argument, it gets the value of the property if the argument is a string or array, and sets the value of the property if the argument is an object.

JQuery’s CSS () method determines what to do by determining the type of the parameter.

Take a look at the source code in jQuery 3.3.1

// name indicates the attribute name
// value Indicates the attribute value
css: function( name, value ) {
	return access( this.function( elem, name, value ) {
		var styles, len,
			map = {},
			i = 0;

		// Check whether the attribute name is an array
		// Call jquery.css to pass in the name of each attribute to get the style
		if ( Array.isArray( name ) ) {
			styles = getStyles( elem );
			len = name.length;

			for(; i < len; i++ ) { map[ name[ i ] ] = jQuery.css( elem, name[ i ],false, styles );
			}

			return map;
		}

		// If value is not undefined, call jquery.style to set the style
		// If value is undefined, call jquery.css to get the style
		returnvalue ! = =undefined ?
			jQuery.style( elem, name, value ) :
			jQuery.css( elem, name );
	}, name, value, arguments.length > 1 );
}
Copy the code

The CSS () method relies on three methods:

Jquery.access (), which gets or sets one or more property values

The jquery.access () method has this code

// Set multiple property values
// If the attribute name (key) is of type object, the object is traversed
// Call the access() method once, passing in the property name and value this time
if ( jQuery.type( key ) === "object" ) {
	chainable = true;
	for ( i in key ) {
		jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
	}

// Set a value
} else if( value ! = =undefined) {... }Copy the code

This is the method that helps CSS () determine whether the first argument is a string or an object.

2, jquery.style () method: read/set style attribute on DOM node

In the CSS () method, if a second argument is passed, which is the value of the property to be set, the jquery.style () method is called to set the style

3, jquery.css () : Reads the DOM style value on the DOM element

The jquery.css () method is added via jquery.extend (), and the CSS () method we started with is added via jquery.fn.extend ().

Jquery.extend () differs from jquery.fn.extend ()

Jquery.extend () adds class methods (static methods) to jQuery classes that need to be called from jQuery classes (called directly with $.xxx);

Jquery.fn.extend () adds members (instance methods) to jQuery classes that can be called directly by all jQuery instances (with $().xxx).

Benefits of overloading

Overloading is a combination of similar functions into a single function, reusing the function name. If the CSS () method in jQuery does not use overloading, then there are 5 different functions to complete the function. Then we need to remember 5 different function names, and the corresponding parameter number and type of each function, obviously more trouble.

conclusion

Although JavaScript doesn’t really have overloading, overloading is quite common in JavaScript, such as the splice() method of arrays, where one argument can be deleted, two arguments can be partially deleted, and three arguments can be deleted before new elements are added. The parseInt() method, for example, takes an argument and determines whether to parse it in hexadecimal or decimal. If it takes two arguments, it uses the second argument as the base of the number.

The method mentioned in this paper to achieve the overload effect is to judge the parameters in essence, whether it is to judge the number of parameters, or to determine the type of parameters, according to the different parameters, to decide what operation to execute.

Although overloading can bring us a lot of convenience, but should not be abused, do not combine some unrelated functions into a function, that does not make sense.

reference

On JavaScript function overloading

How does JS implement overloading

JavaScript function overloading