简体   繁体   English

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

[英]Where am I going wrong in my recursive function?

I am working on a learning project that requires me to implement a recursive function that stringifies a passed in object, without using JSON.stringify. 我正在做一个学习项目,需要我实现一个递归函数,该函数对传入的对象进行字符串化处理,而无需使用JSON.stringify。 I have to consider all data types as parameters that my function will receive, and while I am fine with that, I seem to be getting confused when an array/object is passed, and I call the function on itself to iterate over the object contents. 我必须将所有数据类型都视为函数可以接收的参数,尽管我对此表示满意,但是当传递数组/对象时,我似乎会感到困惑,我自己调用函数以遍历对象内容。 I am not doing it right and every change I make is impacting other areas I thought I had completed so my frustration is starting to win this battle. 我做的不对,我所做的每项变更都会影响我认为已经完成的其他领域,因此我的挫败感开始赢得这场战斗。 Areas I need help on: 我需要帮助的领域:

  1. Output all elements of an array/object in the same way as JSON.stringify when I call the function on itself. 当我自己调用函数时,以与JSON.stringify相同的方式输出数组/对象的所有元素。 An example of an issue I see is, if I pass an array like ["SO"] , I am am getting [SO] returned, but it looks like I have that possibility covered! 我看到的一个问题示例是,如果我传递类似["SO"]的数组,我将得到[SO]返回,但是看起来我已经涵盖了这种可能性!

  2. What to do when a function is passed as a param, which is not allowed. 不允许将函数作为参数传递时该怎么办。

Here is what I have so far. 这是我到目前为止所拥有的。 I appreciate any help you can offer. 感谢您提供的任何帮助。

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 + "}";
    }
};

It is far from perfect as I am still learning so please let me know where I can improve along with any help in getting this to work as is. 由于我仍在学习中,这还远非完美,因此,请让我知道我可以在哪些方面进行改进,以及在使此功能按原样工作方面的任何帮助。

Output all elements of an array/object in the same way as JSON.stringify when I call the function on itself. 当我自己调用函数时,以与JSON.stringify相同的方式输出数组/对象的所有元素。 An example of an issue I see is, if I pass an array like ["SO"], I am am getting [SO] returned, but it looks like I have that possibility covered! 我看到的一个问题示例是,如果我传递[[SO]]之类的数组,我将得到[SO]返回,但是看起来我已经涵盖了这种可能性!

Your recursion of var val in obj is only passing in val , which is the key of obj . var val in objvar val in obj递归仅传递val ,这是obj的键。 You need to call myJSONRecursiveFunc(obj[val]) in order to get the right result. 您需要调用myJSONRecursiveFunc(obj[val])以获得正确的结果。 Additionally, this is true for your array. 此外,对于您的阵列也是如此。 Your if statement needs to check to see if obj[i] is an array, not i which would just be an integer. 您的if语句需要检查obj[i]是否是一个数组,而不是i ,它只是一个整数。 In this case, you need to say: 在这种情况下,您需要说:

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

What to do when a function is passed as a param, which is not allowed. 不允许将函数作为参数传递时该怎么办。

You would need to have a check to see if the function being passed in is a function, with typeof , such as: if (typeof func === function) 您需要检查传入的函数是否是具有typeof的函数,例如: if (typeof func === function)

This is a pretty fun exercise. 这是一个非常有趣的练习。 I did this a few months back, and had access to the Underscore library to do so. 几个月前,我这样做了,并且可以访问Underscore库。 Here's working code: 这是工作代码:

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();
  }
};

Okay, let's do this. 好吧,让我们这样做。

Annotated suggestions 带注释的建议

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( ',' ) + '}'
    }
};

Your error 你的错误

For the record, when you pass in ['SO'] into your function, this is what is happening. 作为记录,当您将['SO']传递给函数时,就是这种情况。 The isArray block catches the object first. isArray块首先捕获对象。

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

Then inside your loop, the else block returns "" + obj[i] + "" , which converts to "" + "SO" + "" , which turns into "SO" . 然后在循环中, else块返回"" + obj[i] + "" ,将其转换为"" + "SO" + "" ,将其转换为"SO"

When this is returned, "[" + "SO" + "]" turns into "[SO]" . 返回时, "[" + "SO" + "]"变为"[SO]"

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

Additional Suggestions 其他建议

When you loop over obj as an actual object near the end, you do so like this. 当您将obj作为最后的实际对象循环时,您将像这样进行操作。

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

Sidenote: val is actually the key, so that's a bit misleading. 旁注: val实际上是关键,因此有点误导。

This is an ugly part of Javascript. 这是Javascript的丑陋部分。 If the raw Object is modified, for example: Object.prototype.foobar = 5 , then 'foobar':5 will show up in every object in your program. 如果原始Object被修改,例如: Object.prototype.foobar = 5 ,则'foobar':5将出现在程序中的每个对象中。 It's worth noting that only developers who are very sure what they are doing should ever be doing this, but it is possible. 值得注意的是,只有非常确定自己在做什么的开发人员才应该这样做,但这是可能的。

To make sure this does not break your program, add the following code. 为确保这不会破坏您的程序,请添加以下代码。

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

obj.hasOwnProperty( <name> ) checks if obj has a direct property <name> . obj.hasOwnProperty( <name> )检查obj是否具有直接属性<name> If it does not, then we skip to the next loop iteration with continue . 如果没有,那么我们将continue使用continue跳到下一个循环迭代。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM