Как я могу предварительно установить аргументы в вызове функции JavaScript? (Частичное Применение Функции)
Я пытаюсь написать функцию JavaScript, которая вернет свой первый аргумент(функцию) со всеми остальными своими аргументами в качестве заданных параметров для этой функции.
Так:
function out(a, b) { document.write(a + " " + b); } function setter(...) {...} setter(out, "hello")("world"); setter(out, "hello", "world")();
выводит "hello world" дважды. для некоторой реализации сеттера
я столкнулся с проблемой манипулирования массивом аргументов с моей первой попытки, но, похоже, есть лучший способ сделать это.
6 ответов:
прежде всего, вам нужно частичное - есть разница между частичным и карри - и вот все, что вам нужно,без рамки:
function partial(func /*, 0..n args */) { var args = Array.prototype.slice.call(arguments, 1); return function() { var allArguments = args.concat(Array.prototype.slice.call(arguments)); return func.apply(this, allArguments); }; }
Теперь, используя Ваш пример, вы можете сделать именно то, что вам нужно:
partial(out, "hello")("world"); partial(out, "hello", "world")(); // and here is my own extended example var sayHelloTo = partial(out, "Hello"); sayHelloTo("World"); sayHelloTo("Alex");
The
partial()
функция может быть использована для реализации, но не каррирование. Вот цитата из сообщение в блоге на разница:где частичное приложение принимает функцию и из нее строит функцию, которая принимает меньше аргументов, карринг строит функции, которые принимают несколько аргументов по составу функций, каждая из которых принимает один аргумент.
надеюсь, что это поможет.
и Карри javascript то, что вы ищете?
если вы используете Додзе вы просто называете додзе.hitch () это делает почти точно то, что вы хотите. Почти-потому что он может быть использован для упаковки контекста, а также. Но ваш пример первый:
dojo.hitch(out, "hello")("world"); dojo.hitch(out, "hello", "world")();
а также:
var A = { sep: ", ", out: function(a, b){ console.log(a + this.sep + b); } }; // using functions in context dojo.hitch(A, A.out, "hello")("world"); dojo.hitch(A, A.out, "hello", "world")(); // using names in context dojo.hitch(A, "out", "hello")("world"); dojo.hitch(A, "out", "hello", "world")();
додзе.hitch () является частью базы Dojo, поэтому, как только вы включили dojo.js это там для вас.
еще один общий объект доступен в dojox.ленг.функциональная.модуль Карри (документирован в функциональная забава в JavaScript с Додзе - просто посмотрите на этой странице для "карри"). В частности, вы можете посмотреть на curry () и partial().
curry () накапливает аргументы (как в вашем примере), но с одним отличием: как только arity удовлетворен, он вызывает функцию, возвращающую значение. Реализация вашего примера:
df.curry(out)("hello")("world"); df.curry(out)("hello", "world");
обратите внимание, что последняя строка не имеет "()" в конце - она вызывается автоматически.
partial () позволяет заменить аргументы при случайная:
df.partial(out, df.arg, "world")("hello");
используя Javascript
apply()
, вы можете изменитьfunction prototype
Function.prototype.pass = function() { var args = arguments, func = this; return function() { func.apply(this, args); } };
вы можете назвать его как
out.pass('hello','world')
apply
принимает массив для 2-го аргумента / параметра.
arguments
это свойство доступно внутри функции, которая содержит все параметры в массиве, как структура.еще один распространенный способ сделать это-использовать
bind
loadedFunc = func.bind(this, v1, v2, v3);
затем
loadedFunc() === this.func(v1,v2,v3);
это своего рода достаточно, хотя и немного некрасиво.
** Изменить: см. ответ Джейсона Бантинга. Этот ответ фактически показывает суб-парный способ цепочки многочисленных исходящих вызовов, а не один выходящий вызов с предустановками для некоторых аргументов. Если этот ответ действительно помогает с подобной проблемой, вы должны обязательно использовать apply и call, как рекомендует Джейсон, а не неясный способ использования eval, который я придумал. **
хорошо... ваш выход будет на самом деле писать "неопределенный" много в этом... но это должно быть близко к тому, что вы хочу:
function out(a, b) { document.write(a + " " + b); } function getArgString( args, start ) { var argStr = ""; for( var i = start; i < args.length; i++ ) { if( argStr != "" ) { argStr = argStr + ", "; } argStr = argStr + "arguments[" + i + "]" } return argStr; } function setter(func) { var argStr = getArgString( arguments, 1 ); eval( "func( " + argStr + ");" ); var newSettter = function() { var argStr = getArgString( arguments, 0 ); if( argStr == "" ) { argStr = "func"; } else { argStr = "func, " + argStr; } return eval( "setter( " + argStr + ");" ); } return newSettter; } setter(out, "hello")("world"); setter(out, "hello", "world")();
Я бы, вероятно, переместил код в getArgString в саму функцию setter... немного безопаснее, так как я использовал 'ивала.
вы могли бы использовать
Function.prototype.bind()
для этого. Это дополнение ES5.в дополнение к общему usecase установки контекста функции (
this
значение), он также может установить частичные аргументы.function out(a, b) { document.write(a + " " + b); } function setter(func) { return func.bind.apply(func, [window].concat([].slice.call(arguments).slice(1))); } setter(out, "hello")("world"); setter(out, "hello", "world")();
мой