我的递归函数在哪里出错了?

时间:2015-05-31 01:12:57

标签: javascript arrays recursion

我正在开发一个学习项目,该项目要求我实现一个递归函数,该函数将传入的对象进行字符串化,而不使用JSON.stringify。我必须将所有数据类型视为我的函数将接收的参数,虽然我很好,但是当传递数组/对象时我似乎感到困惑,并且我自己调用函数来迭代对象内容。 我做得不对,我所做的每一项改变都影响到我认为已经完成的其他领域,所以我的挫折感开始赢得这场战斗。我需要帮助的领域:

  1. 当我自己调用函数时,以与JSON.stringify相同的方式输出数组/对象的所有元素。我看到的问题的一个示例是,如果我传递像["SO"]这样的数组,我将返回[SO],但看起来我有这种可能性!

  2. 当函数作为参数传递时该怎么办,这是不允许的。

  3. 这是我到目前为止所拥有的。我感谢您提供的任何帮助。

    var myJSONRecursiveFunc = function (obj) {
    
        var stringed = "";
        var result;
    
        if (Number.isInteger(obj)) {
            return "" + obj + "";
        } else if (obj === null) {
            return "" + null + "";
        } else if (typeof obj === "boolean") {
            return "" + obj + "";
        } else if (typeof obj === "string") {
            return '"' + obj + '"';
        } else if (Array.isArray(obj)) {
            if (obj.length === 0) {
                return "[" + obj + "]";
            }
            for (var i = 0; i < obj.length; i++) {
                if (Array.isArray(i)) {
                    myJSONRecursiveFunc(i);
                } else {
                    stringed += "" + obj[i] + ""
                }
            }
            return result = "[" + stringed + "]";
        } else {
            for (var val in obj) {
                if (typeof val === "object") {
                    myJSONRecursiveFunc(val);
                }
                stringed += "" + val + "" + ":" + "" + obj[val] + "" + '';
            }
            return result = "{" + stringed + "}";
        }
    };
    

    这还远非完美,因为我还在学习,所以请让我知道我可以改进的地方以及让它按原样工作的任何帮助。

2 个答案:

答案 0 :(得分:1)

  

当我自己调用函数时,以与JSON.stringify相同的方式输出数组/对象的所有元素。我看到的问题的一个例子是,如果我传递像[&#34; SO&#34;]这样的数组,我正在返回[SO],但看起来我已经覆盖了这种可能性!

var val in obj的递归仅传递val,这是obj的关键。您需要致电myJSONRecursiveFunc(obj[val])才能获得正确的结果。此外,这适用于您的阵列。你的if语句需要检查obj[i]是否是一个数组,而不是i,它只是一个整数。在这种情况下,您需要说:

if (Array.isArray(obj[i])) {
  myJSONRecursiveFunc(obj[i])
}
  

当函数作为参数传递时该怎么办,这是不允许的。

您需要检查传入的函数是否为typeof函数,例如:if (typeof func === function)

这是一项非常有趣的练习。几个月前我做了这个,并且可以访问Underscore库。这是工作代码:

var stringifyJSON = function(obj) {
  //Strings and null should be addressed here. Strings have quotes inside the string so I can't lump them together with booleans and numbers.
  if (_.isString(obj)){
    return '"' + obj.split('"').join('\\"') + '"';
  }
  if (_.isNull(obj)){
    return 'null';
  }
  //Arrays get a temporary array that their stringified elements get pushed to, and then that temporary array is joined together and concatenated with the brackets that exist within the returned string.
  if (_.isArray(obj)){
    var tempArr = [];
      _.each(obj, function(elem){
        tempArr.push(stringifyJSON(elem));
      });
    return '[' + tempArr.join(',') + ']';
  }
  //Objects get a temporary string to add their stringified data to. Including a check for undefined values and function keys.
  if (_.isObject(obj)){
      var tempArr = [];
      for (var k in obj){
        if (_.isUndefined(obj[k]) || _.isFunction(k)){
          return '{}';
        } else {
          tempArr.push(stringifyJSON(k) + ':' + stringifyJSON(obj[k]));
        }
      }
      return '{' + tempArr.join(', ') + '}';
  }
  //Everything else = booleans, numbers
  else {
    return obj.toString();
  }
};

答案 1 :(得分:1)

好的,让我们这样做。

带注释的建议

function toJSON(obj) {

    // There are people who will disagree with me
    // but I think this variable is declared way too early.
    // It's used in 2 places as a temp variable, so should
    // be declared closer to where it's used.
    // It should also be named more appropriately for how it's used.
    // I used `arrayParts` and `keyValuePairs` instead.

    var stringed = "";

    // As far as I can tell, this variable is never actually
    // used for anything useful.
    // It's always `return result = <thing>`.
    // If you're immediately returning, there's no need to save
    // to a variable.
    var result;

    if (Number.isInteger(obj)) {
        // The initial `"" + <number>` converts to a string.
        // Appending another "" to the end is pointless in
        // all of the below lines.
        return "" + obj + "";
    } else if (obj === null) {
        return "" + null + "";
    } else if (typeof obj === "boolean") {
        return "" + obj + "";
    } else if (typeof obj === "string") {
        return '"' + obj + '"';
    } else if (Array.isArray(obj)) {
        // If the object is an array with length 0, you
        // already know what it looks like.
        // It's `[]`, so just return that instead of adding
        // the empty array in the middle.
        if (obj.length === 0) {
            return "[" + obj + "]";
        }

        for (var i = 0; i < obj.length; i++) {
            // In the top of this function, you handle all the
            // different types of objects, so you should recurse and
            // reuse that logic. Checking again here is wasted effort.
            if (Array.isArray(i)) {
                myJSONRecursiveFunc(i);
            } else {
                stringed += "" + obj[i] + ""
            }
        }
        return result = "[" + stringed + "]";
        // A better way to write this section would have
        // looked like this.
        //   var arrayParts = []
        //   for( var i = 0; i < obj.length; i++ ){
        //     var stringifiedElement = toJSON( obj[ i ] )
        //     arrayParts.push( stringifiedElement )
        //   }
        //   return '[' + arrayParts.join( ',' ) + ']'
    } else {
        for (var val in obj) {
            // Again, your function's start checks type and handles it.
            // Use that recursively.
            if (typeof val === "object") {
                myJSONRecursiveFunc(val);
            }
            stringed += "" + val + "" + ":" + "" + obj[val] + "" + '';
        }
        return result = "{" + stringed + "}";
        // This section could be rewritten as:
        //   var keyValuePairs = []
        //   for( var key in obj ){
        //     var pair = '"' + key + '":' + toJSON( obj[ key ] )
        //     keyValuePairs.push( pair )
        //   }
        //   return '{' + keyValuePairs.join( ',' ) + '}'
    }
};

您的错误

为了记录,当你将[&#39; SO&#39;]传入你的功能时,这就是正在发生的事情。 isArray块首先捕获对象。

} else if( Array.isArray( obj ) ){

然后在你的循环中,else块返回"" + obj[i] + "",转换为"" + "SO" + "",转换为"SO"

返回此内容后,"[" + "SO" + "]"会变为"[SO]"

   for (var i = 0; i < obj.length; i++) {
        if (Array.isArray(i)) {
            myJSONRecursiveFunc(i);
        } else {
            stringed += "" + obj[i] + "" // <-- the error
        }
    }

其他建议

当你将obj作为接近结尾的实际对象循环时,你会这样做。

for( var val in obj ){
  // foo
}

旁注:val实际上是关键,因此有点误导。

这是Javascript的丑陋部分。如果修改了原始Object,例如:Object.prototype.foobar = 5,则'foobar':5将显示在程序中的每个对象中。值得注意的是,只有非常确定他们正在做什么的开发人员应该这样做,但这是可能的。

要确保这不会破坏您的程序,请添加以下代码。

for( var key in obj ){
  if( ! obj.hasOwnProperty( key ) ){
    continue
  }
}

obj.hasOwnProperty( <name> )检查obj是否有直接属性<name>。如果没有,那么我们使用continue跳转到下一个循环迭代。