这是一个有效的递归函数吗?

时间:2015-12-09 03:28:42

标签: javascript reactjs ecmascript-6 redux redux-devtools

我在库中发现了一个非常混乱的递归表达式。 代码在这里: https://github.com/tappleby/redux-batched-subscribe/blob/master/src/index.js#L22

export function batchedSubscribe(batch) {
  if (typeof batch !== 'function') {
    throw new Error('Expected batch to be a function.');
  }

  const listeners = [];

  function subscribe(listener) {
    listeners.push(listener);

    return function unsubscribe() {
      const index = listeners.indexOf(listener);
      listeners.splice(index, 1);
    };
  }

  function notifyListenersBatched() {
    batch(() => listeners.slice().forEach(listener => listener()));
  }

  return next => (...args) => {
    const store = next(...args);
    const subscribeImmediate = store.subscribe;

    function dispatch(...dispatchArgs) {
      const res = store.dispatch(...dispatchArgs);
      notifyListenersBatched();
      return res;
    }

    return {
      ...store,
      dispatch,
      subscribe,
      subscribeImmediate
    };
  };
}

特别是这部分:

return next => (...args) => {
  const store = next(...args);
  const subscribeImmediate = store.subscribe;

  function dispatch(...dispatchArgs) {
    const res = store.dispatch(...dispatchArgs);
    notifyListenersBatched();
    return res;
  }

  return {
    ...store,
    dispatch,
    subscribe,
    subscribeImmediate
  };
};

这怎么不是无限递归?

2 个答案:

答案 0 :(得分:3)

  

这怎么不是无限递归?

这里绝对没有递归。语法next => (...args) => …不会转换为

return function next(...args) {
    const store = next(...args);
    …

而是

return function(next) {
    return function(...args) {
        const store = next(...args);
        …

因此,除非该函数的调用者做出像var f = batchedSubscribe(…); f(f)(f)…;这样奇怪的事情,否则它不会自行调用。

答案 1 :(得分:2)

我们两个似乎对此感到困惑的原因是因为箭头函数(如果写为单个语句)隐式调用return

例如,像这样的简单函数:

const add = (a, b) => a + b;

相当于

var add = function(a, b) {
  return a + b;
}

知道这一点,我们可以去除糖并转换箭头功能:

return next => function(...args) { // body }

这是真的发生了什么,如果我们更进一步,我们得到这个:

return function(next) {
  return function(...args) {
    const store = next(...args);
    const subscribeImmediate = store.subscribe;

    function dispatch(...dispatchArgs) {
      const res = store.dispatch(...dispatchArgs);
      notifyListenersBatched();
      return res;
    }

    return {
      ...store,
      dispatch,
      subscribe,
      subscribeImmediate
    };
  }
}

包含代码的两个函数实际上都是无名的。 next是一个函数,但不是返回的函数之一。它作为变量传递给第一个返回的函数。

这里没有递归,而是很多函数组合,这可以从像redux这样从函数式编程中吸取大量资源的库中获得。