区分对递归函数的初始和连续调用

时间:2014-03-24 23:41:13

标签: javascript function recursion

我的广泛问题是区分JavaScript中递归函数的初始和连续调用的最简单方法。

Lemme举个例子......

如果在初始调用中传递给函数的字符串为空,我希望以下函数返回false。有没有办法在不向函数添加其他参数的情况下执行此操作?

function isPalindrome(str) {
   if (str.length <= 1) {
     return true;
   }
   if (str.charAt(0) !== str.charAt(str.length -1)) {
     return false;
   }
   return isPalindrome(str.substr(1, str.length - 2));
}

isPalindrome('') // returns true, but I want this to return false
是的,我知道上面的函数可以更简单地写成:

function isPalindrome(str) {
  return str == str.split('').reverse().join('');
}

但是我把它重新定义为一个递归函数来解决更广泛的问题......

3 个答案:

答案 0 :(得分:3)

不要试图区分不同的调用 - 函数的结果不应该依赖于副作用,也不应该在调用堆栈上。

相反,使用第二个执行不同功能的函数:

function isPalindrome(str) {
   return str.length <= 1 ||
     str.charAt(0) == str.charAt(str.length-1) && isPalindrome(str.slice(1, -1));
}
function isNonEmptyPalindrome(str) {
   return str.length > 0 && isPalindrome(str);
}

答案 1 :(得分:0)

您可以使用嵌套函数,即使名称相同:

function isPalindrome(str) {

  // The code out here is for the initial call:
  if (str === '')
    return false;

  // Then do the recursive call
  return function isPalindrome(str) {
    // within this scope, isPalindrome refers to this function

    if (str.length <= 1) {
      return true;
    }
    if (str.charAt(0) !== str.charAt(str.length -1)) {
      return false;
    }
    return isPalindrome(str.substr(1, str.length - 2));
  }(str); // call this function immediately

}

对于一般形式:

function name(arg) {

    // Setup code before initial call
    //////////////////////////////

    var retVal = function name(arg) {
      // recursive routine code
    }(arg);

    // Cleanup code after recursion completes
    /////////////////////////////////////////

    return retVal;
}

Demo using factorial

答案 2 :(得分:0)

这与Bergi的答案基本相同,但是在 isPalindrome 中声明了辅助函数,因此它不会在其他地方使用。

回文的一个更好的例子是,应删除所有标点符号,并将字母全部用大写或小写(以便比较不区分大小写),但仅限于第一次调用。在那之后,比较字符很简单。

长度==零部分也只处理一次,如果没有可供比较的字符,则不会递归调用该函数。

以下进行初始处理,然后调用内部函数。

使用函数声明而不是命名函数表达式,因为后者具有undesirable side effects in IE

  function isPalindrome(s) {

    // Initial processing only on first call
    // remove all punctuation
    s = s.replace(/[^a-z0-9]/ig,'').toLowerCase();

    return s.length == 0? false : doCheck(s);

    function doCheck(s) {

      if (s.length > 1) {

        if (s.substr(0,1) == s.substr(s.length - 1, 1)) {
          s = s.substr(1, s.length - 2);
          return s.length? doCheck(s) : true;

        } else {
          return false;
        }
      }
      return true;
    }
  }

  console.log(isPalindrome("Madam I'm Adam"));  // true
  console.log(isPalindrome("Madam I'm Addam")); // false