Динамические параметры для метапрограммирования в JavaScript?

Я хочу делегировать несколько методов из одного JavaScript-объекта в другой. Поэтому я подумал об использовании метапрограммирования, чтобы несколько методов не определялись просто как делегаты. Пока я остановился на этом методе:

function delegate_to(_method, _obj) {
  return function(_args) { // One parameter, what's about multiple parameters?
    return _obj[_method](_args)
  }
}

Итак, в качестве примера кода, как это должно работать:

var that = {}
var delegate = {}
that.foo = function(_message) { console.log("foo: " + _message) }
that.bar = function(_message) { console.log("bar: " + _message) }
that.baz = function(_message) { console.log("baz: " + _message) }

function delegate_to(_method, _obj) {
  return function(_args) { // One parameter, what's about multiple parameters?
    return _obj[_method](_args)
  }
}

['foo', 'bar', 'baz'].forEach(function(method) {
  delegate[method] = delegate_to(method, that)
})

delegate.foo('Hello JS') // foo: Hello JS
delegate.bar('Hello JS') // bar: Hello JS
delegate.baz('Hello JS') // baz: Hello JS

Код работает, но что, если я хочу делегировать метод, который имеет более одного параметра? Как насчет n параметров? Можно ли изменить код, чтобы иметь любое количество параметров? Это работает в любом браузере?

С уважением, Райнер


person Rainer Jung    schedule 14.12.2012    source источник
comment
Я бы не назвал это метапрограммированием. Это простое функциональное программирование.   -  person JohnB    schedule 14.12.2012


Ответы (2)


Функция имеет методы, называемые «применить», для передачи переменного количества параметров в виде массива. См. MDC:Function.apply

Вы можете преобразовать все параметры, переданные в функцию, в массив с помощью
Array.prototype.slice.call(arguments, 0)

Используя эти два принципа, я изменил ваш код, чтобы он принимал несколько параметров. См. JSBin http://jsbin.com/iwiwix/3/watch.

Соответствующий фрагмент кода:

delegate.foo('Hello JS', "from foo"); // foo: Hello JS



function delegate_to(_method, _obj) {
  return function() {
    var argArray =  Array.prototype.slice.call(arguments, 0);
    return _obj[_method].apply(_obj, argArray);
  };
}



that.foo = function() { console.log("foo: " + arguments[0] + ' ' + arguments[1]); };
person closure    schedule 14.12.2012

Попробуй это:

function delegate_to(_method, _obj) {
  return function() {
    return _obj[_method].apply(_obj, [].slice.call(arguments))
  }
}
person dencey    schedule 14.12.2012
comment
Аргументы не являются массивом, вы не можете вызвать срез на нем легально. - person closure; 14.12.2012
comment
@raghavv да, ты прав, я забыл об этом, внесена правка. - person dencey; 14.12.2012
comment
лучший способ - Array.prototype.slice.call(arguments, 0), поскольку вы без необходимости создаете пустой массив. - person closure; 14.12.2012
comment
Да, у меня это сработало, спасибо! Какая разница с другим ответом, использующим Array.prototype.slice.call(arguments, 0)? - person Rainer Jung; 14.12.2012
comment
Хорошо, я только что получил ответ. Спасибо! - person Rainer Jung; 14.12.2012
comment
В общем, вы правы, он строит новый массив, но я думаю, что эта разница мизерная, я просто использую удобный способ. - person dencey; 14.12.2012