Динамични параметри за метапрограмиране в 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