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

Posted

技术标签:

【中文标题】我可以在 $.getJSON 函数中使用递归 JavaScript 函数吗?【英文标题】:Can I have a recursive JavaScript function inside a $.getJSON function? 【发布时间】:2015-12-30 16:47:00 【问题描述】:

我有一个深度可变的 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 上加载页面时,我没有收到任何错误,页面上也没有任何内容。我究竟做错了什么?我已将所有 JS 包含在 $.getJSON 调用中,因此不会出现异步问题。

将来我还想包含一个正则表达式检查,以便我可以提取具有特定字符串的值,例如/http/。最好的方法是什么?

【问题讨论】:

您能否为我们复制此 JSON 的完整结构? 添加错误处理程序....可能是解析错误或请求失败。我们无法知道,但您需要隔离问题。还要检查浏览器开发工具网络中的实际请求以获取线索 @Pointy 我认为如果appendTo jquery 的东西在某种程度上超出了getText 函数并且不是每次都被调用,那么将links 作为一个全局变量会很有意义。 @AbbasMashayekh,appendTo jquery 的东西应该getText 之外并且只调用一次。 【参考方案1】:

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

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】:

尝试将您的函数定义移到事件处理程序之外:

 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】:

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

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

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

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

在您的情况下,您需要为 JSON 响应数组中返回的每个对象调用它。因此,您也可以将其放在迭代器中。这里为了方便我使用了jQuery的$.each()

/* 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 */
&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"&gt;&lt;/script&gt;

【讨论】:

【参考方案4】:

由于其他答案涵盖了您应该考虑的大部分内容,我想我只会针对您的实际问题发布解决方案。 :)

您想遍历任意 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]

这个sn-p会在上面的json中搜索some_key1,它的值以blah开头:

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');
);
&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"&gt;&lt;/script&gt;

【讨论】:

以上是关于我可以在 $.getJSON 函数中使用递归 JavaScript 函数吗?的主要内容,如果未能解决你的问题,请参考以下文章

getJSON 在 iOS 上的 Cordova 2.1.0 中不起作用

函数等待返回直到 $.getJSON 完成

在 $.getJSON 中使用 $.each()

$.getJSON 函数期间设置的变量只能在函数内访问

$.getJSON 在 IE8 中返回缓存数据

使用命名函数作为 jQuery 中 $.getJSON 的回调来满足 Facebook 请求签名需求