JavaScript: рекурсивная анонимная функция? - PullRequest
109 голосов
/ 07 октября 2010

Допустим, у меня есть базовая рекурсивная функция:

function recur(data) {
    data = data+1;
    var nothing = function() {
        recur(data);
    }
    nothing();
}

Как я могу это сделать, если у меня есть анонимная функция, такая как ...

(function(data){
    data = data+1;
    var nothing = function() {
        //Something here that calls the function?
    }
    nothing();
})();

Мне нужен способ вызова функции, вызвавшей эту функцию ... Я где-то видел сценарии (не помню где), которые могут сообщить вам имя вызываемой функции, но я не могу вспомните любую эту информацию прямо сейчас.

Ответы [ 19 ]

2 голосов
/ 07 февраля 2015

Я не уверен, что ответ все еще требуется, но это также можно сделать с помощью делегатов, созданных с помощью function.bind:

    var x = ((function () {
        return this.bind(this, arguments[0])();
    }).bind(function (n) {
        if (n != 1) {
            return n * this.bind(this, (n - 1))();
        }
        else {
            return 1;
        }
    }))(5);

    console.log(x);

Это не включает именованные функции или arguments.callee.

1 голос
/ 07 октября 2010

Как написал Бобинс, просто назовите вашу функцию.

Но, полагаю, вы также хотите передать начальное значение и в конце концов остановить свою функцию!

var initialValue = ...

(function recurse(data){
    data++;
    var nothing = function() {
        recurse(data);
    }
    if ( ... stop condition ... )
        { ... display result, etc. ... }
    else
        nothing();
}(initialValue));

рабочий пример jsFiddle (использует данные + = данные для развлечения)

1010 *
*

1 голос
/ 09 мая 2017

С ES2015 мы можем немного поиграться с синтаксисом и злоупотреблять стандартными параметрами и блоками.Последние являются просто функциями без аргументов:

const applyT = thunk => thunk();

const fib = n => applyT(
  (f = (x, y, n) => n === 0 ? x : f(y, x + y, n - 1)) => f(0, 1, n)
);

console.log(fib(10)); // 55

// Fibonacci sequence: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55...

Обратите внимание, что f - это параметр с анонимной функцией (x, y, n) => n === 0 ? x : f(y, x + y, n - 1) в качестве значения по умолчанию.Когда f вызывается applyT, этот вызов должен выполняться без аргументов, поэтому используется значение по умолчанию.Значением по умолчанию является функция, и, следовательно, f является именованной функцией, которая может вызывать себя рекурсивно.

1 голос
/ 12 ноября 2015

Мне понадобилась (точнее, хотела) анонимная однострочная функция, чтобы пройти по объекту, создающему строку, и обработала ее следующим образом:

var cmTitle = 'Root' + (function cmCatRecurse(cmCat){return (cmCat == root) ? '' : cmCatRecurse(cmCat.parent) + ' : ' + cmCat.getDisplayName();})(cmCurrentCat);

, которая создает строку типа 'Root: foo: bar: baz: ... '

0 голосов
/ 07 ноября 2018

Еще одно решение Y-комбинатора, использующее ссылку rosetta-code (я думаю, кто-то ранее упоминал ссылку где-то в stackOverflow.

Стрелки для анонимных функций более читабельны для меня:1005 *

var Y = f => (x => x(x))(y => f(x => y(y)(x)));
0 голосов
/ 20 декабря 2016

Это версия ответа @ zem с функциями стрелок.

Вы можете использовать комбинатор U или Y.Y комбинатор является самым простым в использовании.

U комбинатор, при этом вы должны продолжать передавать функцию: const U = f => f(f) U(selfFn => arg => selfFn(selfFn)('to infinity and beyond'))

Y комбинатор, с этим у вас нетчтобы продолжить передачу функции: const Y = gen => U(f => gen((...args) => f(f)(...args))) Y(selfFn => arg => selfFn('to infinity and beyond'))

0 голосов
/ 14 апреля 2015

Другой ответ, который не включает именованную функцию или arguments.callee

var sum = (function(foo,n){
  return n + foo(foo,n-1);
})(function(foo,n){
     if(n>1){
         return n + foo(foo,n-1)
     }else{
         return n;
     }
},5); //function takes two argument one is function and another is 5

console.log(sum) //output : 15
0 голосов
/ 09 мая 2016

Это доработка ответа jforjs с разными именами и слегка измененной записью.

// function takes two argument: first is recursive function and second is input
var sum = (function(capturedRecurser,n){
  return capturedRecurser(capturedRecurser, n);
})(function(thisFunction,n){
     if(n>1){
         return n + thisFunction(thisFunction,n-1)
     }else{
         return n;
     }
},5); 

console.log(sum) //output : 15

Не было необходимости развертывать первую рекурсию. Функция, получающая себя в качестве эталона, возвращает нас к изначальному источнику ООП.

0 голосов
/ 02 октября 2015

Это может работать не везде, но вы можете использовать arguments.callee для ссылки на текущую функцию.

Итак, факториал можно сделать так:

var fac = function(x) { 
    if (x == 1) return x;
    else return x * arguments.callee(x-1);
}
...