我可以在$ .getJSON函数中使用递归JavaScript函数吗?

时间:2015-10-02 13:01:17

标签: javascript jquery json regex recursion

我有一个可变深度的JSON文档。一个例子:

[
    {
        "type": "firsttype",
        "text": {
            "id": "content"
        }
    }
]

我要做的是检索某些键的值,比如说text。由于我不知道这些密钥在.JSON中可能出现在哪里,我需要使用递归函数。然后我尝试在HTML文件中显示这些键和值。

我在这里有一个初步尝试:

$.getJSON("file.json", function getText (oValue, sKey) {
    links = [];
    if (typeof oValue == "object" || typeof oValue == "array") {
        for (i in oValue) {
            getText (oValue [i], i);
        }
    } else {
        links.push ( "<li id='" + oValue + "'>" + sKey + "</li>" );
    }

    $( "<ul/>", {
        "class": "my-new-list",
        html: links.join( "" )
    }).appendTo( "body" );
});

当我在本地或远程或python -m SimpleHTTPServer加载页面时,我没有错误,页面上没有任何内容。我究竟做错了什么?我在$.getJSON调用中包含了所有JS,因此不会出现异步问题。

将来我还希望包含一个regexp检查,以便我可以使用某个字符串提取值,例如/http/。最好的方法是什么?

4 个答案:

答案 0 :(得分:1)

由于其他答案涵盖了您应该考虑的大部分事项,我想我会为您的实际问题发布一个解决方案。 :)

您希望遍历任意JSON并搜索特定键,并且可能对其值有条件。然后,您希望返回指定键的所有值(如果指定,则传递您的条件)。

考虑一下你有以下json:

{
    "hello": "some text",
    "object": {
        "key1": "hello!",
        "key2": "Bye!"
    },
    "array": [{
        "some_key1": "blah blah blah",
        "some_key2": 24
    }, {
        "some_key1": "ghiojd",
        "some_key2": 13
    }],
    "numeric_array": [2, 3, 4, 5]
}

此代码段会在上面的json中搜索some_key1,其值以blah开头:

&#13;
&#13;
function regexpConditionFactory(regex) {
    return function(value) { return regex.test(value); };
}

function searchObjectForKey(obj, key, condition, result) {
    if ($.isPlainObject(obj)) {
        if (obj.hasOwnProperty(key)) {
            if (!condition || ($.isFunction(condition) && condition(obj[key])))
                result.push(obj[key]);
        }
    }

    if ($.isPlainObject(obj) || $.isArray(obj)) {
        for (var k in obj) {
            if (obj.hasOwnProperty(k))
                searchObjectForKey(obj[k], key, condition, result);
        }
    }
}

$.getJSON('file.json', function(data) {
    var res = [];

    searchObjectForKey(data, 'some_key1', regexpConditionFactory(/^blah/), res);

    $('<ul/>', {
        'class': 'my-new-list',
        'html': res.map(function(value) { return '<li>' + value + '</li>'; }).join('')
    }).appendTo('body');
});
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

我认为您的错误在于变量链接的声明: 它必须在我认为的递归函数之外。 在函数内部,它每次都会重新初始化。

var links = [];

$.getJSON("file.json", function getText (oValue, sKey) {

         if (typeof oValue == "object" || typeof oValue == "array") {
            for (i in oValue) {
                getText (oValue [i], i);
                }
         } else {
                links.push ( "<li id='" + oValue + "'>" + sKey + "</li>" );
           }

           $( "<ul/>", {
                       "class": "my-new-list",
                       html: links.join( "" )
           }).appendTo( "body" );
});

答案 2 :(得分:0)

尝试在事件处理程序之外移动函数定义:

 function getText (links, oValue, sKey) {


         if (typeof oValue == "object" || typeof oValue == "array") {
            for (i in oValue) {
                getText (links, oValue [i], i);
                }
         } else {
             if(oValue && sKey)
                links.push ( "<li id='" + oValue + "'>" + sKey + "</li>" );
         }

           $( "<ul/>", {
                       "class": "my-new-list",
                       html: links.join( "" )
           }).appendTo( "body" );
};

$.getJSON("file.json", function(data, success){
  var links = [];  

  getText (links, data, 0);
});

如果有错误,请随意编辑。

目的是将链接数组传递给递归函数,并避免将命名函数定义与getJSON混合,至少要清楚,并确保您可以传递初始化的sKey。

答案 3 :(得分:0)

你可以,但在你的情况下,你可能不应该

可以传递一个命名函数作为回调函数 - 这对于递归很有用(参见:Using Named Callback Functions In Javascript Methods,Ben Nadel) - 但在你的情况下,你可能不应该。

根据您的示例,在调用递归函数之前和之后,您需要执行一些操作。这些事情,例如声明变量和向主体附加元素,需要在递归之外[一次]发生。

因此,传递一个匿名函数作为包含递归函数定义的回调函数,并根据需要调用它。

在您的情况下,您将要为JSON响应数组中返回的每个对象调用它。所以,你也可以把它放在迭代器里面。为方便起见,我在这里使用了jQuery&#39; $.each()

&#13;
&#13;
/* FUNCTION THAT MAKES JSON REQUEST */
function doJsonThing() {
  
  /* BEGIN REWRITE OF OP's EXAMPLE CODE */
  $.getJSON('file.json', function (json) {
    var links = [];
    function getText (key, val) {
      if (typeof val === 'object' || typeof val === 'array') {
        for (i in val) {
          getText(i, val[i]);
        }
      } else {
        links.push('<li id="' + val + '">' + key + ' (' + val + ')</li>' );
      }
    }
    $.each(json, function (key, val) {
      getText(key, val);
    });
    $('<ul/>', {
      "class": "my-new-list",
      "html" : links.join('')
    }).appendTo('body');
  });
  /* END REWRITE OF EXAMPLE CODE */
  
}

/* THE FOLLOWING IS NOT PART OF THE EXAMPLE,
// IT IS JUST USED TO SIMULATE A SERVER RESPONSE */

/* BEGIN UNIT TEST */
// CREATE CLOSURE TO RETURN DUMMY FUNCTION AND FAKE RESPONSE
function json_response(response) {
  return function (url, success) {
    success(response);
  };
}

// OVERRIDE $.getJSON WITH DUMMY FUNCTION AND FAKE RESPONSE
$.getJSON = json_response(
  
  // SIMULATED CONTENTS OF 'file.json'
  $.parseJSON(
    '['
  + '  {'
  + '    "type": "firsttype",'
  + '    "text": {'
  + '      "id": "content"'
  + '    }'
  + '  },'
  + '  {'
  + '    "type": "secondtype",'
  + '    "text": {'
  + '      "id": "other"'
  + '    }'
  + '  }'
  + ']'
  )
);
doJsonThing();
/* END UNIT TEST */
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
&#13;
&#13;
&#13;