Перегрузка функций в Javascript - лучшие практики - PullRequest
711 голосов
/ 19 января 2009

Как лучше всего подделать перегрузку функций в Javascript?

Я знаю, что невозможно перегрузить функции в Javascript, как в других языках. Если мне нужна была функция с двумя вариантами использования foo(x) и foo(x,y,z), которая является наилучшей / предпочтительной:

  1. Во-первых, используя разные имена
  2. Использование необязательных аргументов, таких как y = y || 'default'
  3. Использование количества аргументов
  4. Проверка типов аргументов
  5. или как?

Ответы [ 33 ]

1 голос
/ 14 апреля 2019

Нечто подобное можно сделать для перегрузки функций.

function addCSS(el, prop, val) {
  return {
    2: function() {
      // when two arguments are set
      // now prop is an oject
      for (var i in prop) {
          el.style[i] = prop[i];
      }
    },
    3: function() {
      // when three arguments are set
      el.style[prop] = val;
    }
    }[arguments.length]();
}
// usage
var el = document.getElementById("demo");
addCSS(el, "color", "blue");
addCSS(el, {
    "backgroundColor": "black",
  "padding": "10px"
});

Источник

1 голос
/ 01 ноября 2017

Для вашего случая использования вот как я бы справился с этим с ES6 (так как это уже конец 2017 года):

const foo = (x, y, z) => {
  if (y && z) {
    // Do your foo(x, y, z); functionality
    return output;
  }
  // Do your foo(x); functionality
  return output;
}

Очевидно, что вы можете адаптировать его для работы с любым количеством параметров и просто соответствующим образом изменить свои условные операторы.

1 голос
/ 10 сентября 2013

Первый вариант действительно заслуживает внимания, потому что я подошел к довольно сложной настройке кода. Итак, мой ответ

  1. Использование разных имен в первую очередь

С небольшой, но важной подсказкой имена должны отличаться для компьютера, но не для вас. Назовите перегруженные функции, такие как: func, func1, func2.

1 голос
/ 24 июля 2017

По состоянию на июль 2017 года, следующая техника была общей. Обратите внимание, что мы также можем выполнять проверку типов внутри функции.

function f(...rest){   // rest is an array
   console.log(rest.length);
   for (v of rest) if (typeof(v)=="number")console.log(v);
}
f(1,2,3);  // 3 1 2 3
1 голос
/ 25 ноября 2016

JavaScript - нетипизированный язык, и я думаю, что имеет смысл перегрузить метод / функцию в отношении количества параметров. Следовательно, я бы рекомендовал проверить, был ли параметр определен:

myFunction = function(a, b, c) {
     if (b === undefined && c === undefined ){
          // do x...
     }
     else {
          // do y...
     }
};
1 голос
/ 20 мая 2014

Это старый вопрос, но мне кажется, что нужна еще одна запись (хотя я сомневаюсь, что кто-нибудь прочтет ее). Использование выражений немедленного вызова функций (IIFE) может использоваться в сочетании с замыканиями и встроенными функциями для обеспечения перегрузки функций. Рассмотрим следующий (надуманный) пример:

var foo;

// original 'foo' definition
foo = function(a) {
  console.log("a: " + a);
}

// define 'foo' to accept two arguments
foo = (function() {
  // store a reference to the previous definition of 'foo'
  var old = foo;

  // use inline function so that you can refer to it internally
  return function newFoo(a,b) {

    // check that the arguments.length == the number of arguments 
    // defined for 'newFoo'
    if (arguments.length == newFoo.length) {
      console.log("a: " + a);
      console.log("b: " + b);

    // else if 'old' is a function, apply it to the arguments
    } else if (({}).toString.call(old) === '[object Function]') {
      old.apply(null, arguments);
    }
  }
})();

foo(1);
> a: 1
foo(1,2);
> a: 1
> b: 2
foo(1,2,3)
> a: 1

Короче говоря, использование IIFE создает локальную область, позволяя нам определить личную переменную old для хранения ссылки на начальное определение функции foo. Затем эта функция возвращает встроенную функцию newFoo, которая регистрирует содержимое обоих двух аргументов, если ей передано ровно два аргумента a и b, или вызывает функцию old, если arguments.length !== 2. Этот шаблон может повторяться любое количество раз, чтобы наделить одну переменную несколькими различными функциональными определениями.

0 голосов
/ 01 апреля 2019

в JS нет реальной перегрузки, в любом случае мы все еще можем моделировать перегрузку метода несколькими способами:

метод № 1: использовать объект

function test(x,options){
  if("a" in options)doSomething();
  else if("b" in options)doSomethingElse();
}
test("ok",{a:1});
test("ok",{b:"string"});

метод № 2: использовать остальные параметры (спред)

function test(x,...p){
 if(p[2])console.log("3 params passed"); //or if(typeof p[2]=="string")
else if (p[1])console.log("2 params passed");
else console.log("1 param passed");
}

метод № 3: использовать неопределенное

function test(x, y, z){
 if(typeof(z)=="undefined")doSomething();
}

метод № 4: проверка типа

function test(x){
 if(typeof(x)=="string")console.log("a string passed")
 else ...
}
0 голосов
/ 29 июня 2018

Я использовал эту функцию, чтобы годами предупреждать о перегрузках:

function overload(){
  const fs = arguments, fallback = fs[fs.length - 1];
  return function(){
    const f = fs[arguments.length] || (arguments.length >= fs.length ? fallback : null);
    return f.apply(this, arguments);
  }
}

продемонстрировало,

function curry1(f){
  return curry2(f, f.length);
}

function curry2(f, minimum){
  return function(...applied){
    if (applied.length >= minimum) {
      return f.apply(this, applied);
    } else {
      return curry2(function(...args){
        return f.apply(this, applied.concat(args));
      }, minimum - applied.length);
    }
  }
}

export const curry = overload(null, curry1, curry2);

Взгляните на метод jQuery off:

  function off( types, selector, fn ) {
    var handleObj, type;
    if ( types && types.preventDefault && types.handleObj ) {

        // ( event )  dispatched jQuery.Event
        handleObj = types.handleObj;
        jQuery( types.delegateTarget ).off(
            handleObj.namespace ?
                handleObj.origType + "." + handleObj.namespace :
                handleObj.origType,
            handleObj.selector,
            handleObj.handler
        );
        return this;
    }
    if ( typeof types === "object" ) {

        // ( types-object [, selector] )
        for ( type in types ) {
            this.off( type, selector, types[ type ] );
        }
        return this;
    }
    if ( selector === false || typeof selector === "function" ) {

        // ( types [, fn] )
        fn = selector;
        selector = undefined;
    }
    if ( fn === false ) {
        fn = returnFalse;
    }
    return this.each( function() {
        jQuery.event.remove( this, types, fn, selector );
    } );
  }

Многие перегруженные функции при оптимизации для производительности практически не читаются. Вы должны расшифровать главу функции. Возможно, это быстрее, чем использование функции overload, как я предоставляю; однако с точки зрения человека медленнее определить, какая перегрузка была вызвана.

0 голосов
/ 07 октября 2013

Мы сделали over.js , чтобы решить эту проблему очень элегантно. Вы можете сделать:

var obj = {

  /**
   * Says something in the console.
   *
   * say(msg) - Says something once.
   * say(msg, times) - Says something many times.
   */
  say: Over(
    function(msg$string){
      console.info(msg$string);
    },
    function(msg$string, times$number){
      for (var i = 0; i < times$number; i++) this.say(msg$string);
    }
  )

};
0 голосов
/ 22 ноября 2013

Я работаю над библиотекой, которая предоставляет классные возможности кода для Javascript, в настоящее время она поддерживает конструкторы, наследование, перегрузку методов по количеству параметров и по типам параметров, миксинам, статическим свойствам и синглтонам.

См. Пример перегрузки метода с использованием этой библиотеки:

eutsiv.define('My.Class', {
    constructor: function() {
        this.y = 2;
    },
    x: 3,
    sum: function() {
        return this.x + this.y;
    },
    overloads: {
        value: [
            function() { return this.x + ', ' + this.y },
            function(p1) { this.x = p1; },
            function(p1, p2) { this.x = p1; this.y = p2; }  // will set x and y
        ]
    }
});

var test = new My.Class({ x: 5 });   // create the object
test.value();                        // will return '5, 2'
test.sum();                          // will return 7
test.value(13);                      // will set x to 13
test.value();                        // will return '13, 2'
test.sum();                          // will return 15
test.value(10, 20);                  // will set x to 10 and y to 20
test.value();                        // will return '10, 20'
test.sum();                          // will return 30

Любые отзывы, исправления ошибок, документы и улучшения тестов приветствуются!

https://github.com/eutsiv/eutsiv.js

...