📜 ⬆️ ⬇️

Function overloading in JS

As you know, in JavaScript it is impossible to create several functions that differ only in the list of parameters: the last one created will overwrite the previous ones. About the difference at the level of the types of parameters can not speak at all. Usually, if a programmer wants to create a function with a multiple interface, he writes something like this:
// getRectangleArea(x1, y1, x2, y2) // getRectangleArea(width, height) function getRectangleArea(x1, y1, x2, y2) { if (arguments.length==2) return x1*y1; return (x2-x1)*(y2-y1); } * This source code was highlighted with Source Code Highlighter .
  1. // getRectangleArea(x1, y1, x2, y2) // getRectangleArea(width, height) function getRectangleArea(x1, y1, x2, y2) { if (arguments.length==2) return x1*y1; return (x2-x1)*(y2-y1); } * This source code was highlighted with Source Code Highlighter .
  2. // getRectangleArea(x1, y1, x2, y2) // getRectangleArea(width, height) function getRectangleArea(x1, y1, x2, y2) { if (arguments.length==2) return x1*y1; return (x2-x1)*(y2-y1); } * This source code was highlighted with Source Code Highlighter .
  3. // getRectangleArea(x1, y1, x2, y2) // getRectangleArea(width, height) function getRectangleArea(x1, y1, x2, y2) { if (arguments.length==2) return x1*y1; return (x2-x1)*(y2-y1); } * This source code was highlighted with Source Code Highlighter .
  4. // getRectangleArea(x1, y1, x2, y2) // getRectangleArea(width, height) function getRectangleArea(x1, y1, x2, y2) { if (arguments.length==2) return x1*y1; return (x2-x1)*(y2-y1); } * This source code was highlighted with Source Code Highlighter .
  5. // getRectangleArea(x1, y1, x2, y2) // getRectangleArea(width, height) function getRectangleArea(x1, y1, x2, y2) { if (arguments.length==2) return x1*y1; return (x2-x1)*(y2-y1); } * This source code was highlighted with Source Code Highlighter .
  6. // getRectangleArea(x1, y1, x2, y2) // getRectangleArea(width, height) function getRectangleArea(x1, y1, x2, y2) { if (arguments.length==2) return x1*y1; return (x2-x1)*(y2-y1); } * This source code was highlighted with Source Code Highlighter .
// getRectangleArea(x1, y1, x2, y2) // getRectangleArea(width, height) function getRectangleArea(x1, y1, x2, y2) { if (arguments.length==2) return x1*y1; return (x2-x1)*(y2-y1); } * This source code was highlighted with Source Code Highlighter .

While the example does not look very scary, but over time the interfaces may become noticeably larger, then the function will become poorly readable. See what you can do about it.

Firstly, I would like to write separate functions for each set of parameters like this:
  1. function getRectangleArea (width, height) {
  2. Return width * height;
  3. }
  4. function getRectangleArea (x1, y1, x2, y2) {
  5. return (x2-x1) * (y2-y1);
  6. }
* This source code was highlighted with Source Code Highlighter .

So the code is more beautiful and more logical, you can give the parameters the talking names in each function. One problem: it does not work. But we can write a function generator of the first type, submitting to it a set of subfunctions, as in the second example. Let, to begin with, all the subfunctions have a different number of parameters. The number of function parameters can be recognized by functionName.length , and the number of arguments passed by - by arguments.length . Recall also the great thing apply and write:
  1. function polymorph () {
  2. var len2func = [];
  3. for ( var i = 0; i <arguments.length; i ++)
  4. if ( typeof (arguments [i]) == "function" )
  5. len2func [arguments [i] .length] = arguments [i];
  6. return function () {
  7. return len2func [arguments.length] .apply ( this , arguments);
  8. }
  9. }
* This source code was highlighted with Source Code Highlighter .

The polymorph function takes as arguments a set of subfunctions with a different number of parameters, puts them into an array of len2func , whose index is the number of parameters, and returns a closure function that, depending on the number of arguments, causes a particular subfunction. Use this:
  1. var getRectangleArea2 = polymorph (
  2. function (width, height) {
  3. Return width * height;
  4. },
  5. function (x1, y1, x2, y2) {
  6. return (x2-x1) * (y2-y1);
  7. }
  8. );
* This source code was highlighted with Source Code Highlighter .

Now getRectangleArea2 is a complete analogue of getRectangleArea , however, the code has become much more transparent, and now a comment is no longer required: the ways of using are obvious.

The situation becomes more complicated if we want to support functions with the same number of parameters that differ in types. However, types can be controlled using typeof and instanceof , so it is easy to extend the polymorph() function for these cases as well. Types of parameters will be set in a special object before the function:
  1. var PolyFunc = polymorph (
  2. function (a, b, c) {
  3. return "Three arguments version - any types" ;
  4. },
  5. {i: Number, str: String},
  6. function (i, str) {
  7. return "Number and string passed" ;
  8. },
  9. {re: RegExp},
  10. function (re, a) {
  11. return "RegExp and something else passed" ;
  12. },
  13. {f: Function, b: Boolean},
  14. function (f, b) {
  15. return "Function and boolean passed" ;
  16. },
  17. {f: Function, i: Number},
  18. function (f, i) {
  19. return "Function and number passed" ;
  20. }
  21. );
  22. alert (PolyFunc (1,2,3)); // "Three arguments version - any types"
  23. alert (PolyFunc (1, "qq" )); // "Number and string passed"
  24. alert (PolyFunc ( function () {}, true )); // "Function and boolean passed"
  25. alert (PolyFunc ( function () {}, 1)); // "Function and number passed"
  26. alert (PolyFunc (/ a /, 1)); // "RegExp and something else passed"
  27. alert (PolyFunc (/ a /, "str" )); // "RegExp and something else passed"
* This source code was highlighted with Source Code Highlighter .

The whole thing I put in the Google code, and I will be glad if someone comes in handy. You can overload not only ordinary functions, but also methods and object constructors (examples are by reference), and they can be defined through each other (by calling your version with a different set of parameters). You can use both built-in and user-defined types of parameters. It is possible to modify the already created polymorphic function by adding or replacing some subfunctions.

Unfortunately, you have to pay for beauty and, as always, with speed. The overhead on the function call on my Core2DUO @ 2.66GHz was in FF3.6, IE8, Opera10 and Safari about 1-10 μs (IE the slowest, then FF, then Opera and Safari). Chrome shows the best result in the range of 0.3-1 μs, overtaking FF 10 times. For functions that are fast themselves and are called very often, use caution.

')

Source: https://habr.com/ru/post/86403/


All Articles