Vanilla JS(有趣的一个):从字符串访问深埋的JSON节点的最佳方式;“地图”; 领先

Vanilla JS(有趣的一个):从字符串访问深埋的JSON节点的最佳方式;“地图”; 领先,json,performance,dictionary,parsing,javascript-objects,Json,Performance,Dictionary,Parsing,Javascript Objects,我只是偶然遇到了(一个不那么做作的版本)我在下面列出的情景。我可以想出几十种方法来处理它——从递归函数到将其呈现到DOM,再到使用treewalker——如果我知道JS中有一些晦涩难懂的东西可以处理这个精确的问题,我甚至都不会感到惊讶,我只是不知道 事情是,它比你想象的更像一个面条商。继续读下去。我保证它会钩住你 看,我已经做了25年的JS开发人员了。越来越多地,我的部分职责越来越涉及采访潜在的前端开发人员。我非常喜欢这个问题,把它作为我的“了解应聘者的想法”面试问题之一介绍给我。我真的很感激任

我只是偶然遇到了(一个不那么做作的版本)我在下面列出的情景。我可以想出几十种方法来处理它——从递归函数到将其呈现到DOM,再到使用treewalker——如果我知道JS中有一些晦涩难懂的东西可以处理这个精确的问题,我甚至都不会感到惊讶,我只是不知道

事情是,它比你想象的更像一个面条商。继续读下去。我保证它会钩住你

看,我已经做了25年的JS开发人员了。越来越多地,我的部分职责越来越涉及采访潜在的前端开发人员。我非常喜欢这个问题,把它作为我的“了解应聘者的想法”面试问题之一介绍给我。我真的很感激任何人的意见,我也很想看看人们在野外是如何解决这个问题的

数据结构 好极了。。。假设我有一个巨大(但有效)的JSON对象

让我们称之为n层深度(比如关系数据库转储之类。这里与用例无关;这是我感兴趣的策略),由不同的数据类型(例如数组、对象、字符串、数字、布尔值等)组成

示例对象

    const singledOut = {
    planets: [
        // Author's note: to distinguish these ellipses from the spread operator, I'll italicize 'em :)
        ...
        {"Venus": {...}}, 
        {"Earth": {
            ...
            "composition": [...],
            "continents":  [
                ...
                "Europe":     {...},
                "NorthAmerica"   {
                    ...
                    "climates":    [...],
                    "countries":   [
                        "Canada":        {...}   // ...and so on; you get the idea. Once we've drilled
                        "Mexico":        {...}   // far enough down to get good and granular, assume we'd
                        "UnitedStates":  {...}   // start seeing simple data types (string, numbers, etc)
                                ],
                    "currencies":  [...],            
                    ...
                            },
                "SouthAmerica"   {...},
                ...
            ],
            "craters":     [...]
            ...
        {"Mars":  {...}},
        ...
    ]
}
"planets~Earth~continents~NorthAmerica~countries~UnitedStates~states~California~ ... ~Disneyland~fauna~giant mice"
出于本练习的目的,我们可以假设我们已经——已经加载到内存中——访问了所讨论的JSON对象(也就是说,一些设计极为糟糕的API将我们吐回了这个大的wankin’对象,我们需要从中获得一点点数据),但我们确实知道它的路径


定位器 现在让我们假设我有一个动态生成的、以字符串形式分隔的路径,指向其中包含的某个节点的“地址”。假设我们使用波浪号(~)作为分隔符,并且还声明数据源没有这些字符(或者它们是经过编码的),以避免数据污染/需要处理转义字符

一些深埋的数据信息的样本“路径”

    const singledOut = {
    planets: [
        // Author's note: to distinguish these ellipses from the spread operator, I'll italicize 'em :)
        ...
        {"Venus": {...}}, 
        {"Earth": {
            ...
            "composition": [...],
            "continents":  [
                ...
                "Europe":     {...},
                "NorthAmerica"   {
                    ...
                    "climates":    [...],
                    "countries":   [
                        "Canada":        {...}   // ...and so on; you get the idea. Once we've drilled
                        "Mexico":        {...}   // far enough down to get good and granular, assume we'd
                        "UnitedStates":  {...}   // start seeing simple data types (string, numbers, etc)
                                ],
                    "currencies":  [...],            
                    ...
                            },
                "SouthAmerica"   {...},
                ...
            ],
            "craters":     [...]
            ...
        {"Mars":  {...}},
        ...
    ]
}
"planets~Earth~continents~NorthAmerica~countries~UnitedStates~states~California~ ... ~Disneyland~fauna~giant mice"
假设我们追踪的数据是居住在加利福尼亚州阿纳海姆迪斯尼乐园的大老鼠数量,美国,北美,地球


谜题 所以说真的,这里有四个问题

  • 你不需要全部回答,或者,如果你选择回答
  • 同样的答案不一定适用于所有4种场景(尽管如果你能想到其中一种,我会印象深刻)
  • 场景:

    • 场景一:布局与上述完全相同。你有你的对象,你有你的字符串路径。我们如何将字符串应用到JSON中 得到我们想要的金块

    • 场景二:也与上述相同,但这次我们只有KVP的值部分: `地球~北美~美国~加利福尼亚~橙色~阿纳海姆~游客陷阱~迪斯尼乐园~劳斯莱斯

    • 场景三和场景四:与场景一和场景二相同。。。但是我们不得不从一个字符串(
      JSON.stringify
      'd)开始使用这个巨大的honkin'对象

    所有4项的目标都是以我们能够管理的最小内存占用(即超出已消耗的内存)以最少的步骤/操作检索数据摘要。简言之,一个使用
    JSON.Parse(JSON.stringify())
    chicanery的递归函数(虽然它完全可以工作,但可能不是具有n个递归级别的最佳内存调用,yanno?)

    我们可以假设我们寻找的数据存在于其自身独特的节点中(例如,不是位于所述节点内的一些列举列表中;与“1只狗、4只鸭、2只老鼠、75只金骆驼、53只紫孔雀、95只白波斯猴、1只老虎……和高飞”不同),但确实存在这样的可能性,即所寻求的数据是以某种方式前置或后缀(“已知有2只”、“2只巨鼠”或“迪斯尼乐园收容所2只大屁股啮齿动物”)

    棘手的一点甚至只是将字符串版本的
    “a~sample~path~like~this”
    转换为关键版本的
    [“a”][“sample”][“path”][“like”][“this”]
    在我提出的几乎所有解决方案中效率都低得令人沮丧

    所以我想这到底是怎么回事:地球上最好的开发者住在这个网站上。我会问他们。所有这些都说明,任何形式的JS voodoo都是公平的游戏,但如果有一些古怪的库专门做到这一点,请不要忘记将其重量和足迹纳入您的答案中。包括所有的,比如说ExtJS,仅仅针对这一个问题可能不是一个很好的解决方案


    我迫不及待地想看看结果如何!此外,你永远不会知道:也许你会是我的下一次面试

    我并不自称是javascript专家,更不用说“地球上最好的开发人员之一”,但关于将
    “a~sample~path~like~this”
    转换为
    [“a”][“sample”][“path”][“like”][“this”]
    的关键版本的问题,答案似乎很简单:

    "a~sample~path~like~this".split('~').reduce((a,v)=>a[v], bigObject)
    
    这还不能解决您最初的问题,因为仅仅通过一个键进行索引是不够的。然而,它可以作为一个基础服务器,因为所需要的只是修改简化函数,使其更为通用。但我觉得有点难以回答,因为我不明白你的意思,比如

    "countries": [
        "Canada":  {...}
        "Mexico":  {...}
        "UnitedStates":  {...}
    ]
    
    这远远不是一个有效的JSON(或Javascript)对象,因为数组不能有显式键(数组的元素需要用逗号分隔)。如果你是这个意思:

    "countries": [
        { "Canada":  {...} },
        { "Mexico":  {...} },
        { "UnitedStates":  {...} },
    ]
    
    (这充其量是一种古怪的表现形式),然后您可以使用 ], “像这样的~sample~路径~” .split(“~”) .reduce((a,v)=>a数组实例?a.find(k=>k[v])[v]:a[v], (大对象)

    A