我有一个包含对象和数组的嵌套数据结构。我如何提取信息,即访问一个特定的或多个值(或键)?
例如:
var data = {
code: 42,
items: [{
id: 1,
name: 'foo'
}, {
id: 2,
name: 'bar'
}]
};
我如何访问项目中的第二个项目的名称?
我有一个包含对象和数组的嵌套数据结构。我如何提取信息,即访问一个特定的或多个值(或键)?
例如:
var data = {
code: 42,
items: [{
id: 1,
name: 'foo'
}, {
id: 2,
name: 'bar'
}]
};
我如何访问项目中的第二个项目的名称?
当前回答
以防万一,有人在2017年或以后访问这个问题,并寻找一种容易记住的方法,这里有一篇关于在JavaScript中访问嵌套对象而不被迷惑的详细博客文章
无法读取未定义错误的属性“foo”
1. Oliver Steele的嵌套对象访问模式
最简单、最干净的方法是使用Oliver Steele的嵌套对象访问模式
const name = ((user || {}).personalInfo || {}).name;
用这个符号,你永远不会碰到
无法读取未定义的属性“名称”。
你基本上检查user是否存在,如果不存在,你立即创建一个空对象。这样,下一层键将始终从一个存在的对象或空对象访问,而不会从undefined访问。
2. 使用数组缩减访问嵌套对象
为了能够访问嵌套数组,您可以编写自己的数组reduce util。
const getNestedObject = (nestedObj, pathArr) => {
return pathArr.reduce((obj, key) =>
(obj && obj[key] !== 'undefined') ? obj[key] : undefined, nestedObj);
}
// pass in your object structure as array elements
const name = getNestedObject(user, ['personalInfo', 'name']);
// to access nested array, just pass in array index as an element the path array.
const city = getNestedObject(user, ['personalInfo', 'addresses', 0, 'city']);
// this will return the city from the first address item.
还有一种出色的类型处理最小库类型可以为您完成所有这些。
其他回答
动态方法
在下面的deep(data,key)函数中,您可以使用任意键字符串-在您的情况下,items[1].name(您可以在任何级别使用数组符号[i]) -如果key无效,则返回undefined。
让深= (o, k) = > k.split (' . ') .reduce ((a、c、i) = > { 让m = c.match (/(.*?)\[(\ d *) \] /); 如果(m && a!=null && a[m[1]]!=null) return a[m[1]][+m[2]]; 返回a==null ?答:[c]; }, o); / /测试 Let key = 'items[1].name' //任意深键 Let data = { 42岁的代码: 名称:项目:[{id: 11日“foo”},{id: 22岁的名字:“酒吧”},) }; Console.log (key,'=', deep(data,key));
使用lodash是一个很好的解决方案
例:
var object = { 'a': { 'b': { 'c': 3 } } };
_.get(object, 'a.b.c');
// => 3
这个问题很老了,所以作为当代的更新。随着ES2015的开始,有了其他方法来获取你需要的数据。现在有一个被称为对象解构的特性,用于访问嵌套对象。
Const data = { 42岁的代码: 项目:[{ id: 1、 名称:“foo” }, { id: 2 名称:“酒吧” }) }; const { 项目:[,{ 名称:secondName }) } =数据; console.log (secondName);
上面的例子从名为items的数组的name键创建了一个名为secondName的变量,该数组表示跳过数组中的第一个对象。
值得注意的是,对于这个例子来说,它可能有点过头了,因为简单的数组访问更容易阅读,但在一般情况下,它在分解对象时很有用。
这是对您的特定用例的非常简短的介绍,解构可能是一种不寻常的语法,首先要习惯。我建议阅读Mozilla的解构赋值文档来了解更多信息。
老问题,但没有人提到lodash(只是下划线)。
如果你已经在你的项目中使用lodash,我认为在一个复杂的例子中有一种优雅的方法:
选择1
_.get(response, ['output', 'fund', 'data', '0', 'children', '0', 'group', 'myValue'], '')
一样:
选择2
response.output.fund.data[0].children[0].group.myValue
第一个选项和第二个选项之间的区别是,在Opt 1中,如果你在路径中缺少一个属性(未定义),你不会得到错误,它会返回第三个参数。
对于数组过滤器,lodash有_.find(),但我宁愿使用常规的filter()。但我仍然认为上面的方法_.get()在处理非常复杂的数据时非常有用。我在过去遇到过非常复杂的api,它很方便!
我希望它能对那些正在寻找操作标题所暗示的真正复杂数据的选项的人有用。
如果您试图在JSON字符串中查找路径,可以将数据转储到https://jsonpathfinder.com并单击GUI元素。它将生成元素路径的JS语法。
除此之外,对于您可能想要迭代的任何数组,用循环替换相关的数组偏移下标,如[0]。
这里有一个简单版本的工具,你可以在这里或在https://ggorlen.github.io/json-dive/上运行。单击要将路径复制到剪贴板的节点。
/* code minified to make the tool easier to run without having to scroll */ let bracketsOnly=!1,lastHighlighted={style:{}};const keyToStr=t=>!bracketsOnly&&/^[a-zA-Z_$][a-zA-Z$_\d]*$/.test(t)?`.${toHTML(t)}`:`["${toHTML(t)}"]`,pathToData=t=>`data-path="data${t.join("")}"`,htmlSpecialChars={"&":"&","<":"<",">":">",'"':""","'":"'","\t":"\\t","\r":"\\r","\n":"\\n"," ":" "},toHTML=t=>(""+t).replace(/[&<>"'\t\r\n ]/g,t=>htmlSpecialChars[t]),makeArray=(t,e)=>`\n [<ul ${pathToData(e)}>\n ${t.map((t,a)=>{e.push(`[${a}]`);const n=`<li ${pathToData(e)}>\n ${pathify(t,e).trim()},\n </li>`;return e.pop(),n}).join("")}\n </ul>]\n`,makeObj=(t,e)=>`\n {<ul ${pathToData(e)}>\n ${Object.entries(t).map(([t,a])=>{e.push(keyToStr(t));const n=`<li ${pathToData(e)}>\n "${toHTML(t)}": ${pathify(a,e).trim()},\n </li>`;return e.pop(),n}).join("")}\n </ul>}\n`,pathify=(t,e=[])=>Array.isArray(t)?makeArray(t,e):"object"==typeof t&&t!=null?makeObj(t,e):toHTML("string"==typeof t?`"${t}"`:t),defaultJSON='{\n "corge": "test JSON... \\n asdf\\t asdf",\n "foo-bar": [\n {"id": 42},\n [42, {"foo": {"baz": {"ba r<>!\\t": true, "4quux": "garply"}}}]\n ]\n}',$=document.querySelector.bind(document),$$=document.querySelectorAll.bind(document),resultEl=$("#result"),pathEl=$("#path"),tryToJSON=t=>{try{resultEl.innerHTML=pathify(JSON.parse(t)),$("#error").innerText=""}catch(t){resultEl.innerHTML="",$("#error").innerText=t}},copyToClipboard=t=>{const e=document.createElement("textarea");e.textContent=t,document.body.appendChild(e),e.select(),document.execCommand("copy"),document.body.removeChild(e)},flashAlert=(t,e=2e3)=>{const a=document.createElement("div");a.textContent=t,a.classList.add("alert"),document.body.appendChild(a),setTimeout(()=>a.remove(),e)},handleClick=t=>{t.stopPropagation(),copyToClipboard(t.target.dataset.path),flashAlert("copied!"),$("#path-out").textContent=t.target.dataset.path},handleMouseOut=t=>{lastHighlighted.style.background="transparent",pathEl.style.display="none"},handleMouseOver=t=>{pathEl.textContent=t.target.dataset.path,pathEl.style.left=`${t.pageX+30}px`,pathEl.style.top=`${t.pageY}px`,pathEl.style.display="block",lastHighlighted.style.background="transparent",(lastHighlighted=t.target.closest("li")).style.background="#0ff"},handleNewJSON=t=>{tryToJSON(t.target.value),[...$$("#result *")].forEach(t=>{t.addEventListener("click",handleClick),t.addEventListener("mouseout",handleMouseOut),t.addEventListener("mouseover",handleMouseOver)})};$("textarea").addEventListener("change",handleNewJSON),$("textarea").addEventListener("keyup",handleNewJSON),$("textarea").value=defaultJSON,$("#brackets").addEventListener("change",t=>{bracketsOnly=!bracketsOnly,handleNewJSON({target:{value:$("textarea").value}})}),handleNewJSON({target:{value:defaultJSON}}); /**/ *{box-sizing:border-box;font-family:monospace;margin:0;padding:0}html{height:100%}#path-out{background-color:#0f0;padding:.3em}body{margin:0;height:100%;position:relative;background:#f8f8f8}textarea{width:100%;height:110px;resize:vertical}#opts{background:#e8e8e8;padding:.3em}#opts label{padding:.3em}#path{background:#000;transition:all 50ms;color:#fff;padding:.2em;position:absolute;display:none}#error{margin:.5em;color:red}#result ul{list-style:none}#result li{cursor:pointer;border-left:1em solid transparent}#result li:hover{border-color:#ff0}.alert{background:#f0f;padding:.2em;position:fixed;bottom:10px;right:10px} <!-- --> <div class="wrapper"><textarea></textarea><div id="opts"><label>brackets only: <input id="brackets"type="checkbox"></label></div><div id="path-out">click a node to copy path to clipboard</div><div id="path"></div><div id="result"></div><div id="error"></div></div>
Unminified(也可以在GitHub上找到):
let bracketsOnly = false; let lastHighlighted = {style: {}}; const keyToStr = k => !bracketsOnly && /^[a-zA-Z_$][a-zA-Z$_\d]*$/.test(k) ? `.${toHTML(k)}` : `["${toHTML(k)}"]` ; const pathToData = p => `data-path="data${p.join("")}"`; const htmlSpecialChars = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'", "\t": "\\t", "\r": "\\r", "\n": "\\n", " ": " ", }; const toHTML = x => ("" + x) .replace(/[&<>"'\t\r\n ]/g, m => htmlSpecialChars[m]) ; const makeArray = (x, path) => ` [<ul ${pathToData(path)}> ${x.map((e, i) => { path.push(`[${i}]`); const html = `<li ${pathToData(path)}> ${pathify(e, path).trim()}, </li>`; path.pop(); return html; }).join("")} </ul>] `; const makeObj = (x, path) => ` {<ul ${pathToData(path)}> ${Object.entries(x).map(([k, v]) => { path.push(keyToStr(k)); const html = `<li ${pathToData(path)}> "${toHTML(k)}": ${pathify(v, path).trim()}, </li>`; path.pop(); return html; }).join("")} </ul>} `; const pathify = (x, path=[]) => { if (Array.isArray(x)) { return makeArray(x, path); } else if (typeof x === "object" && x !== null) { return makeObj(x, path); } return toHTML(typeof x === "string" ? `"${x}"` : x); }; const defaultJSON = `{ "corge": "test JSON... \\n asdf\\t asdf", "foo-bar": [ {"id": 42}, [42, {"foo": {"baz": {"ba r<>!\\t": true, "4quux": "garply"}}}] ] }`; const $ = document.querySelector.bind(document); const $$ = document.querySelectorAll.bind(document); const resultEl = $("#result"); const pathEl = $("#path"); const tryToJSON = v => { try { resultEl.innerHTML = pathify(JSON.parse(v)); $("#error").innerText = ""; } catch (err) { resultEl.innerHTML = ""; $("#error").innerText = err; } }; const copyToClipboard = text => { const ta = document.createElement("textarea"); ta.textContent = text; document.body.appendChild(ta); ta.select(); document.execCommand("copy"); document.body.removeChild(ta); }; const flashAlert = (text, timeoutMS=2000) => { const alert = document.createElement("div"); alert.textContent = text; alert.classList.add("alert"); document.body.appendChild(alert); setTimeout(() => alert.remove(), timeoutMS); }; const handleClick = e => { e.stopPropagation(); copyToClipboard(e.target.dataset.path); flashAlert("copied!"); $("#path-out").textContent = e.target.dataset.path; }; const handleMouseOut = e => { lastHighlighted.style.background = "transparent"; pathEl.style.display = "none"; }; const handleMouseOver = e => { pathEl.textContent = e.target.dataset.path; pathEl.style.left = `${e.pageX + 30}px`; pathEl.style.top = `${e.pageY}px`; pathEl.style.display = "block"; lastHighlighted.style.background = "transparent"; lastHighlighted = e.target.closest("li"); lastHighlighted.style.background = "#0ff"; }; const handleNewJSON = e => { tryToJSON(e.target.value); [...$$("#result *")].forEach(e => { e.addEventListener("click", handleClick); e.addEventListener("mouseout", handleMouseOut); e.addEventListener("mouseover", handleMouseOver); }); }; $("textarea").addEventListener("change", handleNewJSON); $("textarea").addEventListener("keyup", handleNewJSON); $("textarea").value = defaultJSON; $("#brackets").addEventListener("change", e => { bracketsOnly = !bracketsOnly; handleNewJSON({target: {value: $("textarea").value}}); }); handleNewJSON({target: {value: defaultJSON}}); * { box-sizing: border-box; font-family: monospace; margin: 0; padding: 0; } html { height: 100%; } #path-out { background-color: #0f0; padding: 0.3em; } body { margin: 0; height: 100%; position: relative; background: #f8f8f8; } textarea { width: 100%; height: 110px; resize: vertical; } #opts { background: #e8e8e8; padding: 0.3em; } #opts label { padding: 0.3em; } #path { background: black; transition: all 0.05s; color: white; padding: 0.2em; position: absolute; display: none; } #error { margin: 0.5em; color: red; } #result ul { list-style: none; } #result li { cursor: pointer; border-left: 1em solid transparent; } #result li:hover { border-color: #ff0; } .alert { background: #f0f; padding: 0.2em; position: fixed; bottom: 10px; right: 10px; } <div class="wrapper"> <textarea></textarea> <div id="opts"> <label> brackets only: <input id="brackets" type="checkbox"> </label> </div> <div id="path-out">click a node to copy path to clipboard</div> <div id="path"></div> <div id="result"></div> <div id="error"></div> </div>
这并不是为了代替学习如何钓鱼,但一旦你知道了,可以节省时间。