如何访问和处理嵌套对象、数组或 JSON?

发布于 2025-01-12 06:52:46 字数 275 浏览 1 评论 0 原文

我有一个包含对象和数组的嵌套数据结构。如何提取信息,即访问特定或多个值(或键)?

例如:

var data = {
    code: 42,
    items: [{
        id: 1,
        name: 'foo'
    }, {
        id: 2,
        name: 'bar'
    }]
};

我如何访问 items 中第二个项目的 name

I have a nested data structure containing objects and arrays. How can I extract the information, i.e. access a specific or multiple values (or keys)?

For example:

var data = {
    code: 42,
    items: [{
        id: 1,
        name: 'foo'
    }, {
        id: 2,
        name: 'bar'
    }]
};

How could I access the name of the second item in items?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(30

旧情勿念 2025-01-19 06:52:46

预备知识

JavaScript 只有一种可以包含多个值的数据类型:对象数组是一种特殊形式的对象。

(普通)对象具有以下形式

{key: value, key: value, ...}

数组具有以下形式

[value, value, ...]

数组和对象都公开一个 key ->;值结构。数组中的键必须是数字,而任何字符串都可以用作对象中的键。键值对也称为“属性”

点表示法或方括号表示法访问属性

const value = obj.someProperty;

如果属性名称不是有效的 JavaScript /#x7.6" rel="noreferrer">标识符名称​​[spec],或者名称是变量的值:

// the space is not a valid character in identifier names
const value = obj["some Property"];

// property name as variable
const name = "some Property";
const value = obj[name];

因此,数组元素只能使用括号表示法访问:

const value = arr[5]; // arr.5 would be a syntax error

// property name / index as variable
const x = 5;
const value = arr[x];

等等...什么关于 JSON?

JSON 是数据的文本表示形式,就像 XML、YAML、CSV 等一样。要处理此类数据,首先必须将其转换为 JavaScript 数据类型,即数组和对象(刚刚解释了如何处理这些数据)。问题 在 JavaScript 中解析 JSON? 解释了如何解析 JSON。

进一步阅读材料

如何访问数组和对象是 JavaScript 基础知识,因此建议阅读



访问嵌套数据结构

嵌套数据结构是一个数组或引用其他数组的对象或对象,即它的值是数组或对象。可以通过连续应用点或括号表示法来访问此类结构。

下面是一个示例:

const data = {
    code: 42,
    items: [{
        id: 1,
        name: 'foo'
    }, {
        id: 2,
        name: 'bar'
    }]
};

假设我们要访问第二个项目的name

下面是我们如何一步一步地做到这一点:

正如我们所看到的,data 是一个对象,因此我们可以使用点表示法访问它的属性。 items 属性的访问方式如下:

data.items

该值是一个数组,要访问其第二个元素,我们必须使用方括号表示法:

data.items[1]

该值是一个对象,我们再次使用点表示法来访问 name 属性。所以我们最终得到:

const item_name = data.items[1].name;

或者,我们可以对任何属性使用括号表示法,特别是如果名称包含使其对点表示法使用无效的字符:

const item_name = data['items'][1]['name'];

我正在尝试访问属性,但我只得到 未定义回来?

大多数情况下,当您遇到未定义时,对象/数组根本不具有具有该名称的属性。

const foo = {bar: {baz: 42}};
console.log(foo.baz); // undefined

使用 console.log 或 < a href="https://developer.mozilla.org/en-US/docs/DOM/console.dir" rel="noreferrer">console.dir 并检查结构对象/数组。您尝试访问的属性实际上可能是在嵌套对象/数组上定义的。

console.log(foo.bar.baz); // 42

如果属性名称是动态的并且我事先不知道它们怎么办?

如果属性名称未知或者我们想要访问对象/数组元素的所有属性,我们可以使用 for...in [MDN] 循环 for对象和 for [MDN] 循环数组以迭代所有属性/元素。

对象

要迭代data的所有属性,我们可以像这样迭代对象

for (const prop in data) {
    // `prop` contains the name of each property, i.e. `'code'` or `'items'`
    // consequently, `data[prop]` refers to the value of each property, i.e.
    // either `42` or the array
}

取决于对象来自哪里(以及您的对象)想做),您可能必须在每次迭代中测试该属性是否确实是对象的属性,或者是继承的属性。您可以使用 Object#hasOwnProperty [MDN]

作为 for...inhasOwnProperty 的替代方案,您可以使用 Object.keys [MDN] 获取一个 数组属性名称

Object.keys(data).forEach(function(prop) {
  // `prop` is the property name
  // `data[prop]` is the property value
});

数组

要迭代data.items数组的所有元素,我们使用for 循环:

for(let i = 0, l = data.items.length; i < l; i++) {
    // `i` will take on the values `0`, `1`, `2`,..., i.e. in each iteration
    // we can access the next element in the array with `data.items[i]`, example:
    // 
    // var obj = data.items[i];
    // 
    // Since each element is an object (in our example),
    // we can now access the objects properties with `obj.id` and `obj.name`. 
    // We could also use `data.items[i].id`.
}

也可以使用 for...in 来迭代数组,但有一些原因应该避免这种情况:为什么是 'for(var item in list)' 和数组在 JavaScript 中被认为是不好的做法?

随着 ECMAScript 5 的浏览器支持不断增加,数组方法 forEach [MDN] 也成为一个有趣的替代方案:

data.items.forEach(function(value, index, array) {
    // The callback is executed for each element in the array.
    // `value` is the element itself (equivalent to `array[index]`)
    // `index` will be the index of the element in the array
    // `array` is a reference to the array itself (i.e. `data.items` in this case)
}); 

在支持 ES2015 (ES6) 的环境中,您还可以使用for。 ..of [MDN] 循环,它不仅适用于数组,而且适用于任何 可迭代

for (const item of data.items) {
   // `item` is the array element, **not** the index
}

在每个迭代,for...of 直接为我们提供了可迭代的下一个元素,没有“索引”来访问或使用。


如果我不知道数据结构的“深度”怎么办?

除了未知的键之外,数据结构的“深度”(即有多少个嵌套对象)也可能是未知的。如何访问深度嵌套的属性通常取决于确切的数据结构。

但是,如果数据结构包含重复模式,例如二叉树的表示,则解决方案通常包括 递归[维基百科]访问数据结构的每个级别。

下面是获取二叉树的第一个叶节点的示例:

function getLeaf(node) {
    if (node.leftChild) {
        return getLeaf(node.leftChild); // <- recursive call
    }
    else if (node.rightChild) {
        return getLeaf(node.rightChild); // <- recursive call
    }
    else { // node must be a leaf node
        return node;
    }
}

const first_leaf = getLeaf(root);

const root = {
    leftChild: {
        leftChild: {
            leftChild: null,
            rightChild: null,
            data: 42
        },
        rightChild: {
            leftChild: null,
            rightChild: null,
            data: 5
        }
    },
    rightChild: {
        leftChild: {
            leftChild: null,
            rightChild: null,
            data: 6
        },
        rightChild: {
            leftChild: null,
            rightChild: null,
            data: 7
        }
    }
};
function getLeaf(node) {
    if (node.leftChild) {
        return getLeaf(node.leftChild);
    } else if (node.rightChild) {
        return getLeaf(node.rightChild);
    } else { // node must be a leaf node
        return node;
    }
}

console.log(getLeaf(root).data);

访问具有未知键和深度的嵌套数据结构的更通用方法是测试值的类型并采取相应的操作。

这是一个示例,它将嵌套数据结构内的所有原始值添加到数组中(假设它不包含任何函数)。如果我们遇到一个对象(或数组),我们只需再次对该值调用 toArray (递归调用)。

function toArray(obj) {
    const result = [];
    for (const prop in obj) {
        const value = obj[prop];
        if (typeof value === 'object') {
            result.push(toArray(value)); // <- recursive call
        }
        else {
            result.push(value);
        }
    }
    return result;
}

const data = {
  code: 42,
  items: [{
    id: 1,
    name: 'foo'
  }, {
    id: 2,
    name: 'bar'
  }]
};


function toArray(obj) {
  const result = [];
  for (const prop in obj) {
    const value = obj[prop];
    if (typeof value === 'object') {
      result.push(toArray(value));
    } else {
      result.push(value);
    }
  }
  return result;
}

console.log(toArray(data));



由于复杂对象或数组的结构不一定是显而易见的,因此我们可以检查每一步的值来决定如何进一步移动 console.log [ MDN]console.dir [MDN]帮助我们做到这一点。例如(Chrome 控制台的输出):

> console.log(data.items)
 [ Object, Object ]

在这里我们看到 data.items 是一个包含两个元素的数组,这两个元素都是对象。在 Chrome 控制台中,甚至可以立即扩展和检查对象。

> console.log(data.items[1])
  Object
     id: 2
     name: "bar"
     __proto__: Object

这告诉我们 data.items[1] 是一个对象,展开后我们看到它有三个属性,idname和 __proto__ 。后者是用于对象原型链的内部属性。不过,原型链和继承超出了这个答案的范围。

Preliminaries

JavaScript has only one data type which can contain multiple values: Object. An Array is a special form of object.

(Plain) Objects have the form

{key: value, key: value, ...}

Arrays have the form

[value, value, ...]

Both arrays and objects expose a key -> value structure. Keys in an array must be numeric, whereas any string can be used as key in objects. The key-value pairs are also called the "properties".

Properties can be accessed either using dot notation

const value = obj.someProperty;

or bracket notation, if the property name would not be a valid JavaScript identifier name [spec], or the name is the value of a variable:

// the space is not a valid character in identifier names
const value = obj["some Property"];

// property name as variable
const name = "some Property";
const value = obj[name];

For that reason, array elements can only be accessed using bracket notation:

const value = arr[5]; // arr.5 would be a syntax error

// property name / index as variable
const x = 5;
const value = arr[x];

Wait... what about JSON?

JSON is a textual representation of data, just like XML, YAML, CSV, and others. To work with such data, it first has to be converted to JavaScript data types, i.e. arrays and objects (and how to work with those was just explained). How to parse JSON is explained in the question Parse JSON in JavaScript? .

Further reading material

How to access arrays and objects is fundamental JavaScript knowledge and therefore it is advisable to read the MDN JavaScript Guide, especially the sections



Accessing nested data structures

A nested data structure is an array or object which refers to other arrays or objects, i.e. its values are arrays or objects. Such structures can be accessed by consecutively applying dot or bracket notation.

Here is an example:

const data = {
    code: 42,
    items: [{
        id: 1,
        name: 'foo'
    }, {
        id: 2,
        name: 'bar'
    }]
};

Let's assume we want to access the name of the second item.

Here is how we can do it step-by-step:

As we can see data is an object, hence we can access its properties using dot notation. The items property is accessed as follows:

data.items

The value is an array, to access its second element, we have to use bracket notation:

data.items[1]

This value is an object and we use dot notation again to access the name property. So we eventually get:

const item_name = data.items[1].name;

Alternatively, we could have used bracket notation for any of the properties, especially if the name contained characters that would have made it invalid for dot notation usage:

const item_name = data['items'][1]['name'];

I'm trying to access a property but I get only undefined back?

Most of the time when you are getting undefined, the object/array simply doesn't have a property with that name.

const foo = {bar: {baz: 42}};
console.log(foo.baz); // undefined

Use console.log or console.dir and inspect the structure of object / array. The property you are trying to access might be actually defined on a nested object / array.

console.log(foo.bar.baz); // 42

What if the property names are dynamic and I don't know them beforehand?

If the property names are unknown or we want to access all properties of an object / elements of an array, we can use the for...in [MDN] loop for objects and the for [MDN] loop for arrays to iterate over all properties / elements.

Objects

To iterate over all properties of data, we can iterate over the object like so:

for (const prop in data) {
    // `prop` contains the name of each property, i.e. `'code'` or `'items'`
    // consequently, `data[prop]` refers to the value of each property, i.e.
    // either `42` or the array
}

Depending on where the object comes from (and what you want to do), you might have to test in each iteration whether the property is really a property of the object, or it is an inherited property. You can do this with Object#hasOwnProperty [MDN].

As alternative to for...in with hasOwnProperty, you can use Object.keys [MDN] to get an array of property names:

Object.keys(data).forEach(function(prop) {
  // `prop` is the property name
  // `data[prop]` is the property value
});

Arrays

To iterate over all elements of the data.items array, we use a for loop:

for(let i = 0, l = data.items.length; i < l; i++) {
    // `i` will take on the values `0`, `1`, `2`,..., i.e. in each iteration
    // we can access the next element in the array with `data.items[i]`, example:
    // 
    // var obj = data.items[i];
    // 
    // Since each element is an object (in our example),
    // we can now access the objects properties with `obj.id` and `obj.name`. 
    // We could also use `data.items[i].id`.
}

One could also use for...in to iterate over arrays, but there are reasons why this should be avoided: Why is 'for(var item in list)' with arrays considered bad practice in JavaScript?.

With the increasing browser support of ECMAScript 5, the array method forEach [MDN] becomes an interesting alternative as well:

data.items.forEach(function(value, index, array) {
    // The callback is executed for each element in the array.
    // `value` is the element itself (equivalent to `array[index]`)
    // `index` will be the index of the element in the array
    // `array` is a reference to the array itself (i.e. `data.items` in this case)
}); 

In environments supporting ES2015 (ES6), you can also use the for...of [MDN] loop, which not only works for arrays, but for any iterable:

for (const item of data.items) {
   // `item` is the array element, **not** the index
}

In each iteration, for...of directly gives us the next element of the iterable, there is no "index" to access or use.


What if the "depth" of the data structure is unknown to me?

In addition to unknown keys, the "depth" of the data structure (i.e. how many nested objects) it has, might be unknown as well. How to access deeply nested properties usually depends on the exact data structure.

But if the data structure contains repeating patterns, e.g. the representation of a binary tree, the solution typically includes to recursively [Wikipedia] access each level of the data structure.

Here is an example to get the first leaf node of a binary tree:

function getLeaf(node) {
    if (node.leftChild) {
        return getLeaf(node.leftChild); // <- recursive call
    }
    else if (node.rightChild) {
        return getLeaf(node.rightChild); // <- recursive call
    }
    else { // node must be a leaf node
        return node;
    }
}

const first_leaf = getLeaf(root);

const root = {
    leftChild: {
        leftChild: {
            leftChild: null,
            rightChild: null,
            data: 42
        },
        rightChild: {
            leftChild: null,
            rightChild: null,
            data: 5
        }
    },
    rightChild: {
        leftChild: {
            leftChild: null,
            rightChild: null,
            data: 6
        },
        rightChild: {
            leftChild: null,
            rightChild: null,
            data: 7
        }
    }
};
function getLeaf(node) {
    if (node.leftChild) {
        return getLeaf(node.leftChild);
    } else if (node.rightChild) {
        return getLeaf(node.rightChild);
    } else { // node must be a leaf node
        return node;
    }
}

console.log(getLeaf(root).data);

A more generic way to access a nested data structure with unknown keys and depth is to test the type of the value and act accordingly.

Here is an example which adds all primitive values inside a nested data structure into an array (assuming it does not contain any functions). If we encounter an object (or array) we simply call toArray again on that value (recursive call).

function toArray(obj) {
    const result = [];
    for (const prop in obj) {
        const value = obj[prop];
        if (typeof value === 'object') {
            result.push(toArray(value)); // <- recursive call
        }
        else {
            result.push(value);
        }
    }
    return result;
}

const data = {
  code: 42,
  items: [{
    id: 1,
    name: 'foo'
  }, {
    id: 2,
    name: 'bar'
  }]
};


function toArray(obj) {
  const result = [];
  for (const prop in obj) {
    const value = obj[prop];
    if (typeof value === 'object') {
      result.push(toArray(value));
    } else {
      result.push(value);
    }
  }
  return result;
}

console.log(toArray(data));



Helpers

Since the structure of a complex object or array is not necessarily obvious, we can inspect the value at each step to decide how to move further. console.log [MDN] and console.dir [MDN] help us doing this. For example (output of the Chrome console):

> console.log(data.items)
 [ Object, Object ]

Here we see that that data.items is an array with two elements which are both objects. In Chrome console the objects can even be expanded and inspected immediately.

> console.log(data.items[1])
  Object
     id: 2
     name: "bar"
     __proto__: Object

This tells us that data.items[1] is an object, and after expanding it we see that it has three properties, id, name and __proto__. The latter is an internal property used for the prototype chain of the object. The prototype chain and inheritance is out of scope for this answer, though.

空袭的梦i 2025-01-19 06:52:46

您可以通过这种方式访问​​它

data.items[1].name

,或者

data["items"][1]["name"]

两种方式都是相同的。

You can access it this way

data.items[1].name

or

data["items"][1]["name"]

Both ways are equal.

攀登最高峰 2025-01-19 06:52:46

对象和数组有很多内置方法可以帮助您处理数据。

注意:在许多示例中,我使用箭头函数。它们类似于函数表达式,但它们从词法上绑定 this 值。

Object.keys()Object.values() (ES 2017) 和 Object.entries() (ES 2017)

Object.keys() 返回一个的数组对象的键,Object.values() 返回对象值的数组,Object.entries() 返回对象键的数组以及格式为 的相应值[键,值]

const obj = {
  a: 1
 ,b: 2
 ,c: 3
}

console.log(Object.keys(obj)) // ['a', 'b', 'c']
console.log(Object.values(obj)) // [1, 2, 3]
console.log(Object.entries(obj)) // [['a', 1], ['b', 2], ['c', 3]]

Object.entries() 带有 for-of 循​​环和解构赋值

const obj = {
  a: 1
 ,b: 2
 ,c: 3
}

for (const [key, value] of Object.entries(obj)) {
  console.log(`key: ${key}, value: ${value}`)
}

使用 for-of 循​​环解构赋值

For-of 循​​环允许您迭代数组元素。语法为 for (const element of array) (我们可以将 const 替换为 varlet,但它是如果我们不打算修改 element,最好使用 const)。

解构赋值允许您从数组或对象中提取值并将它们分配给变量。在本例中,const [key, value] 意味着我们不是将 [key, value] 数组分配给 element,而是分配第一个元素该数组的元素为key,第二个元素为value。它等价于:

for (const element of Object.entries(obj)) {
  const key = element[0]
       ,value = element[1]
}

如您所见,解构使这变得更加简单。

Array.prototype.every()< /code>Array.prototype.some()

如果指定的回调函数,every() 方法返回 true对于数组的每个元素返回true。如果指定的回调函数为 some(至少一个)元素返回 true,则 some() 方法返回 true

const arr = [1, 2, 3]

// true, because every element is greater than 0
console.log(arr.every(x => x > 0))
// false, because 3^2 is greater than 5
console.log(arr.every(x => Math.pow(x, 2) < 5))
// true, because 2 is even (the remainder from dividing by 2 is 0)
console.log(arr.some(x => x % 2 === 0))
// false, because none of the elements is equal to 5
console.log(arr.some(x => x === 5))

Array.prototype.find()< /code>Array.prototype.filter()

find() 方法返回满足以下条件的第一个元素提供回调函数。 filter() 方法返回满足所提供的回调函数的所有元素的数组。

const arr = [1, 2, 3]

// 2, because 2^2 !== 2
console.log(arr.find(x => x !== Math.pow(x, 2)))
// 1, because it's the first element
console.log(arr.find(x => true))
// undefined, because none of the elements equals 7
console.log(arr.find(x => x === 7))

// [2, 3], because these elements are greater than 1
console.log(arr.filter(x => x > 1))
// [1, 2, 3], because the function returns true for all elements
console.log(arr.filter(x => true))
// [], because none of the elements equals neither 6 nor 7
console.log(arr.filter(x => x === 6 || x === 7))

Array.prototype.map()< /code>

map() 方法返回一个数组,其中包含对数组元素调用提供的回调函数的结果。

const arr = [1, 2, 3]

console.log(arr.map(x => x + 1)) // [2, 3, 4]
console.log(arr.map(x => String.fromCharCode(96 + x))) // ['a', 'b', 'c']
console.log(arr.map(x => x)) // [1, 2, 3] (no-op)
console.log(arr.map(x => Math.pow(x, 2))) // [1, 4, 9]
console.log(arr.map(String)) // ['1', '2', '3']

Array.prototype.reduce()< /code>

reduce() 方法通过使用两个元素调用提供的回调函数将数组减少为单个值。

const arr = [1, 2, 3]

// Sum of array elements.
console.log(arr.reduce((a, b) => a + b)) // 6
// The largest number in the array.
console.log(arr.reduce((a, b) => a > b ? a : b)) // 3

reduce() 方法采用可选的第二个参数,它是初始值。当您调用reduce() 的数组可以有零个或一个元素时,这非常有用。例如,如果我们想创建一个函数 sum() ,它接受一个数组作为参数并返回所有元素的总和,我们可以这样写:

const sum = arr => arr.reduce((a, b) => a + b, 0)

console.log(sum([]))     // 0
console.log(sum([4]))    // 4
console.log(sum([2, 5])) // 7

Objects and arrays has a lot of built-in methods that can help you with processing data.

Note: in many of the examples I'm using arrow functions. They are similar to function expressions, but they bind the this value lexically.

Object.keys(), Object.values() (ES 2017) and Object.entries() (ES 2017)

Object.keys() returns an array of object's keys, Object.values() returns an array of object's values, and Object.entries() returns an array of object's keys and corresponding values in a format [key, value].

const obj = {
  a: 1
 ,b: 2
 ,c: 3
}

console.log(Object.keys(obj)) // ['a', 'b', 'c']
console.log(Object.values(obj)) // [1, 2, 3]
console.log(Object.entries(obj)) // [['a', 1], ['b', 2], ['c', 3]]

Object.entries() with a for-of loop and destructuring assignment

const obj = {
  a: 1
 ,b: 2
 ,c: 3
}

for (const [key, value] of Object.entries(obj)) {
  console.log(`key: ${key}, value: ${value}`)
}

It's very convenient to iterate the result of Object.entries() with a for-of loop and destructuring assignment.

For-of loop lets you iterate array elements. The syntax is for (const element of array) (we can replace const with var or let, but it's better to use const if we don't intend to modify element).

Destructuring assignment lets you extract values from an array or an object and assign them to variables. In this case const [key, value] means that instead of assigning the [key, value] array to element, we assign the first element of that array to key and the second element to value. It is equivalent to this:

for (const element of Object.entries(obj)) {
  const key = element[0]
       ,value = element[1]
}

As you can see, destructuring makes this a lot simpler.

Array.prototype.every() and Array.prototype.some()

The every() method returns true if the specified callback function returns true for every element of the array. The some() method returns true if the specified callback function returns true for some (at least one) element.

const arr = [1, 2, 3]

// true, because every element is greater than 0
console.log(arr.every(x => x > 0))
// false, because 3^2 is greater than 5
console.log(arr.every(x => Math.pow(x, 2) < 5))
// true, because 2 is even (the remainder from dividing by 2 is 0)
console.log(arr.some(x => x % 2 === 0))
// false, because none of the elements is equal to 5
console.log(arr.some(x => x === 5))

Array.prototype.find() and Array.prototype.filter()

The find() methods returns the first element which satisfies the provided callback function. The filter() method returns an array of all elements which satisfies the provided callback function.

const arr = [1, 2, 3]

// 2, because 2^2 !== 2
console.log(arr.find(x => x !== Math.pow(x, 2)))
// 1, because it's the first element
console.log(arr.find(x => true))
// undefined, because none of the elements equals 7
console.log(arr.find(x => x === 7))

// [2, 3], because these elements are greater than 1
console.log(arr.filter(x => x > 1))
// [1, 2, 3], because the function returns true for all elements
console.log(arr.filter(x => true))
// [], because none of the elements equals neither 6 nor 7
console.log(arr.filter(x => x === 6 || x === 7))

Array.prototype.map()

The map() method returns an array with the results of calling a provided callback function on the array elements.

const arr = [1, 2, 3]

console.log(arr.map(x => x + 1)) // [2, 3, 4]
console.log(arr.map(x => String.fromCharCode(96 + x))) // ['a', 'b', 'c']
console.log(arr.map(x => x)) // [1, 2, 3] (no-op)
console.log(arr.map(x => Math.pow(x, 2))) // [1, 4, 9]
console.log(arr.map(String)) // ['1', '2', '3']

Array.prototype.reduce()

The reduce() method reduces an array to a single value by calling the provided callback function with two elements.

const arr = [1, 2, 3]

// Sum of array elements.
console.log(arr.reduce((a, b) => a + b)) // 6
// The largest number in the array.
console.log(arr.reduce((a, b) => a > b ? a : b)) // 3

The reduce() method takes an optional second parameter, which is the initial value. This is useful when the array on which you call reduce() can has zero or one elements. For example, if we wanted to create a function sum() which takes an array as an argument and returns the sum of all elements, we could write it like that:

const sum = arr => arr.reduce((a, b) => a + b, 0)

console.log(sum([]))     // 0
console.log(sum([4]))    // 4
console.log(sum([2, 5])) // 7

谁的年少不轻狂 2025-01-19 06:52:46

如果您尝试通过 idname 从示例结构中访问 item,而不知道它在数组中的位置,最简单的方法是方法是使用 underscore.js 库:

var data = {
    code: 42,
    items: [{
        id: 1,
        name: 'foo'
    }, {
        id: 2,
        name: 'bar'
    }]
};

_.find(data.items, function(item) {
  return item.id === 2;
});
// Object {id: 2, name: "bar"}

根据我的经验,使用高阶函数而不是 对于for..in 循环生成的代码更容易推理,因此更易于维护。

只是我的2分钱。

In case you're trying to access an item from the example structure by id or name, without knowing it's position in the array, the easiest way to do it would be to use underscore.js library:

var data = {
    code: 42,
    items: [{
        id: 1,
        name: 'foo'
    }, {
        id: 2,
        name: 'bar'
    }]
};

_.find(data.items, function(item) {
  return item.id === 2;
});
// Object {id: 2, name: "bar"}

From my experience, using higher order functions instead of for or for..in loops results in code that is easier to reason about, and hence more maintainable.

Just my 2 cents.

寻找我们的幸福 2025-01-19 06:52:46

有时,使用字符串访问嵌套对象可能是理想的。简单的方法是第一级,例如

var obj = { hello: "world" };
var key = "hello";
alert(obj[key]);//world

但是复杂的 json 往往不是这种情况。随着 json 变得越来越复杂,在 json 中查找值的方法也变得复杂。导航 json 的递归方法是最好的,并且如何利用递归将取决于正在搜索的数据类型。如果涉及条件语句,json 搜索可能是一个很好的工具。

如果正在访问的属性是已知的,但是路径很复杂,例如在这个对象中

var obj = {
 arr: [
    { id: 1, name: "larry" },    
    { id: 2, name: "curly" },
    { id: 3, name: "moe" }
 ]
};

并且你知道你想要获取该对象中数组的第一个结果,也许你想使用

var moe = obj["arr[0].name"];

但是,这会导致异常因为没有具有该名称的对象的属性。能够使用它的解决方案是展平对象的树方面。这可以递归地完成。

function flatten(obj){
 var root = {};
 (function tree(obj, index){
   var suffix = toString.call(obj) == "[object Array]" ? "]" : "";
   for(var key in obj){
    if(!obj.hasOwnProperty(key))continue;
    root[index+key+suffix] = obj[key];
    if( toString.call(obj[key]) == "[object Array]" )tree(obj[key],index+key+suffix+"[");
    if( toString.call(obj[key]) == "[object Object]" )tree(obj[key],index+key+suffix+".");   
   }
 })(obj,"");
 return root;
}

现在,复杂的对象可以被展平

var obj = previous definition;
var flat = flatten(obj);
var moe = flat["arr[0].name"];//moe

这是一个jsFiddle 演示 使用这种方法。

At times, accessing a nested object using a string can be desirable. The simple approach is the first level, for example

var obj = { hello: "world" };
var key = "hello";
alert(obj[key]);//world

But this is often not the case with complex json. As json becomes more complex, the approaches for finding values inside of the json also become complex. A recursive approach for navigating the json is best, and how that recursion is leveraged will depend on the type of data being searched for. If there are conditional statements involved, a json search can be a good tool to use.

If the property being accessed is already known, but the path is complex, for example in this object

var obj = {
 arr: [
    { id: 1, name: "larry" },    
    { id: 2, name: "curly" },
    { id: 3, name: "moe" }
 ]
};

And you know you want to get the first result of the array in the object, perhaps you would like to use

var moe = obj["arr[0].name"];

However, that will cause an exception as there is no property of object with that name. The solution to be able to use this would be to flatten the tree aspect of the object. This can be done recursively.

function flatten(obj){
 var root = {};
 (function tree(obj, index){
   var suffix = toString.call(obj) == "[object Array]" ? "]" : "";
   for(var key in obj){
    if(!obj.hasOwnProperty(key))continue;
    root[index+key+suffix] = obj[key];
    if( toString.call(obj[key]) == "[object Array]" )tree(obj[key],index+key+suffix+"[");
    if( toString.call(obj[key]) == "[object Object]" )tree(obj[key],index+key+suffix+".");   
   }
 })(obj,"");
 return root;
}

Now, the complex object can be flattened

var obj = previous definition;
var flat = flatten(obj);
var moe = flat["arr[0].name"];//moe

Here is a jsFiddle Demo of this approach being used.

小嗲 2025-01-19 06:52:46

要访问嵌套属性,您需要指定其名称,然后搜索对象。

如果您已经知道确切的路径,那么您可以将其硬编码在脚本中,如下所示:

data['items'][1]['name']

这些也可以工作 -

data.items[1].name
data['items'][1].name
data.items[1]['name']

当您事先不知道确切的名称,或者用户是为您提供名称的人时。那么就需要动态地搜索数据结构。有些人在这里建议可以使用 for 循环来完成搜索,但是有一种非常简单的方法可以使用 Array.reduce

const data = { code: 42, items: [{ id: 1, name: 'foo' }, { id: 2, name: 'bar' }] }
const path = [ 'items', '1', 'name']
let result = path.reduce((a,v) => a[v], data)

路径是一种表达方式:首先获取带有键 items 的对象,它恰好是一个数组。然后获取 1-st 元素(0 个索引数组)。最后获取该数组元素中带有键 name 的对象,该对象恰好是字符串 bar

如果您的路径很长,您甚至可以使用 String.split 来使这一切变得更容易 -

'items.1.name'.split('.').reduce((a,v) => a[v], data)

这只是纯 JavaScript,无需使用任何第三方库,如 jQuery 或 lodash。

To access a nested attribute, you need to specify its name and then search through the object.

If you already know the exact path, then you can hardcode it in your script like so:

data['items'][1]['name']

these also work -

data.items[1].name
data['items'][1].name
data.items[1]['name']

When you don't know the exact name before hand, or a user is the one who provides the name for you. Then dynamically searching through the data structure is required. Some suggested here that the search can be done using a for loop, but there is a very simple way to traverse a path using Array.reduce.

const data = { code: 42, items: [{ id: 1, name: 'foo' }, { id: 2, name: 'bar' }] }
const path = [ 'items', '1', 'name']
let result = path.reduce((a,v) => a[v], data)

The path is a way to say: First take the object with key items, which happens to be an array. Then take the 1-st element (0 index arrays). Last take the object with key name in that array element, which happens to be the string bar.

If you have a very long path, you might even use String.split to make all of this easier -

'items.1.name'.split('.').reduce((a,v) => a[v], data)

This is just plain JavaScript, without using any third party libraries like jQuery or lodash.

葮薆情 2025-01-19 06:52:46

这里有 4 种不同的方法来获取 javascript 对象属性:

var data = {
  code: 42,
  items: [{
    id: 1,
    name: 'foo'
  }, {
    id: 2,
    name: 'bar'
  }]
};

// Method 1
let method1 = data.items[1].name;
console.log(method1);

// Method 2
let method2 = data.items[1]["name"];
console.log(method2);

// Method 3
let method3 = data["items"][1]["name"];
console.log(method3);

// Method 4  Destructuring
let { items: [, { name: second_name }] } = data;
console.log(second_name);

Here are 4 different methods mentioned to get the javascript object property:

var data = {
  code: 42,
  items: [{
    id: 1,
    name: 'foo'
  }, {
    id: 2,
    name: 'bar'
  }]
};

// Method 1
let method1 = data.items[1].name;
console.log(method1);

// Method 2
let method2 = data.items[1]["name"];
console.log(method2);

// Method 3
let method3 = data["items"][1]["name"];
console.log(method3);

// Method 4  Destructuring
let { items: [, { name: second_name }] } = data;
console.log(second_name);

归属感 2025-01-19 06:52:46

这是简单的解释:

var data = {
    code: 42,
    items: [{
        id: 1,
        name: 'foo'
    }, {
        id: 2,
        name: 'bar'
    }]
};

/*
1. `data` is object contain `items` object*/
console.log(data);

/*
2. `items` object contain array of two objects as elements*/
console.log(data.items);

/*
3. you need 2nd element of array - the `1` from `[0, 1]`*/
console.log(data.items[1]);

/*
4. and you need value of `name` property of 2nd object-element of array)*/
console.log(data.items[1].name);

It's simple explanation:

var data = {
    code: 42,
    items: [{
        id: 1,
        name: 'foo'
    }, {
        id: 2,
        name: 'bar'
    }]
};

/*
1. `data` is object contain `items` object*/
console.log(data);

/*
2. `items` object contain array of two objects as elements*/
console.log(data.items);

/*
3. you need 2nd element of array - the `1` from `[0, 1]`*/
console.log(data.items[1]);

/*
4. and you need value of `name` property of 2nd object-element of array)*/
console.log(data.items[1].name);

当爱已成负担 2025-01-19 06:52:46

您可以使用 lodash _get 函数:

var object = { 'a': [{ 'b': { 'c': 3 } }] };

_.get(object, 'a[0].b.c');
// => 3

You could use lodash _get function:

var object = { 'a': [{ 'b': { 'c': 3 } }] };

_.get(object, 'a[0].b.c');
// => 3
狼性发作 2025-01-19 06:52:46

这个问题很老了,所以作为当代更新。随着 ES2015 的出现,有其他方法可以获取您所需的数据。现在有一个名为对象解构的功能,用于访问嵌套对象。

const data = {
  code: 42,
  items: [{
    id: 1,
    name: 'foo'
  }, {
    id: 2,
    name: 'bar'
  }]
};

const {
  items: [, {
    name: secondName
  }]
} = data;

console.log(secondName);

上面的示例根据名为 items 的数组中的 name 键创建了一个名为 secondName 的变量,孤独的 , 说跳过数组中的第一个对象。

值得注意的是,对于这个例子来说,它可能有点矫枉过正,因为简单的数组访问更容易阅读,但它在一般情况下分解对象时很有用。

这是对您的特定用例的非常简短的介绍,解构可能是一种不寻常的语法,一开始需要习惯。我建议阅读 Mozilla 的解构赋值文档来了解更多的。

This question is quite old, so as a contemporary update. With the onset of ES2015 there are alternatives to get a hold of the data you require. There is now a feature called object destructuring for accessing nested objects.

const data = {
  code: 42,
  items: [{
    id: 1,
    name: 'foo'
  }, {
    id: 2,
    name: 'bar'
  }]
};

const {
  items: [, {
    name: secondName
  }]
} = data;

console.log(secondName);

The above example creates a variable called secondName from the name key from an array called items, the lonely , says skip the first object in the array.

Notably it's probably overkill for this example, as simple array acccess is easier to read, but it comes in useful when breaking apart objects in general.

This is very brief intro to your specific use case, destructuring can be an unusual syntax to get used to at first. I'd recommend reading Mozilla's Destructuring Assignment documentation to learn more.

拍不死你 2025-01-19 06:52:46
var ourStorage = {


"desk":    {
    "drawer": "stapler"
  },
"cabinet": {
    "top drawer": { 
      "folder1": "a file",
      "folder2": "secrets"
    },
    "bottom drawer": "soda"
  }
};
ourStorage.cabinet["top drawer"].folder2; // Outputs -> "secrets"

//parent.subParent.subsubParent["almost there"]["final property"]

基本上,在每个在其下方展开的后代之间使用一个点,并且当您的对象名称由两个字符串组成时,您必须使用 ["obj Name"] 表示法。否则,只需一个点就足够了;

资料来源: https://learn.freecodecamp .org/javascript-algorithms-and-data-structs/basic-javascript/accessing-nested-objects

添加到此,访问嵌套数组将像这样发生:

var ourPets = [
  {
    animalType: "cat",
    names: [
      "Meowzer",
      "Fluffy",
      "Kit-Cat"
    ]
  },
  {
    animalType: "dog",
    names: [
      "Spot",
      "Bowser",
      "Frankie"
    ]
  }
];
ourPets[0].names[1]; // Outputs "Fluffy"
ourPets[1].names[0]; // Outputs "Spot"

来源:https://learn.freecodecamp.org/ javascript-algorithms-and-data-structs/basic-javascript/accessing-nested-arrays/

另一个描述上述情况的更有用的文档:
https://developer.mozilla.org/en-US /docs/Learn/JavaScript/Objects/Basics#Bracket_notation

通过点遍历进行属性访问:https://developer.mozilla.org/en-US /docs/Web/JavaScript/Reference/Operators/Property_Accessors#Dot_notation

var ourStorage = {


"desk":    {
    "drawer": "stapler"
  },
"cabinet": {
    "top drawer": { 
      "folder1": "a file",
      "folder2": "secrets"
    },
    "bottom drawer": "soda"
  }
};
ourStorage.cabinet["top drawer"].folder2; // Outputs -> "secrets"

or

//parent.subParent.subsubParent["almost there"]["final property"]

Basically, use a dot between each descendant that unfolds underneath it and when you have object names made out of two strings, you must use the ["obj Name"] notation. Otherwise, just a dot would suffice;

Source: https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/basic-javascript/accessing-nested-objects

to add to this, accessing nested Arrays would happen like so:

var ourPets = [
  {
    animalType: "cat",
    names: [
      "Meowzer",
      "Fluffy",
      "Kit-Cat"
    ]
  },
  {
    animalType: "dog",
    names: [
      "Spot",
      "Bowser",
      "Frankie"
    ]
  }
];
ourPets[0].names[1]; // Outputs "Fluffy"
ourPets[1].names[0]; // Outputs "Spot"

Source: https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/basic-javascript/accessing-nested-arrays/

Another more useful document depicting the situation above:
https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Basics#Bracket_notation

Property access via dot walking: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_Accessors#Dot_notation

满身野味 2025-01-19 06:52:46

动态访问多级对象。

var obj = {
  name: "john doe",
  subobj: {
    subsubobj: {
      names: "I am sub sub obj"
    }
  }
};

var level = "subobj.subsubobj.names";
level = level.split(".");

var currentObjState = obj;

for (var i = 0; i < level.length; i++) {
  currentObjState = currentObjState[level[i]];
}

console.log(currentObjState);

工作小提琴: https://jsfiddle.net/andreitodorut/3mws3kjL/

Accessing dynamically multi levels object.

var obj = {
  name: "john doe",
  subobj: {
    subsubobj: {
      names: "I am sub sub obj"
    }
  }
};

var level = "subobj.subsubobj.names";
level = level.split(".");

var currentObjState = obj;

for (var i = 0; i < level.length; i++) {
  currentObjState = currentObjState[level[i]];
}

console.log(currentObjState);

Working fiddle: https://jsfiddle.net/andreitodorut/3mws3kjL/

巡山小妖精 2025-01-19 06:52:46

以防万一,有人在 2017 年或之后访问过这个问题并寻找一种易于记住的方式,这里有一篇关于 访问 JavaScript 中的嵌套对象而不会被

无法读取属性'foo'所 迷惑undefined 错误

1. Oliver Steele 的嵌套对象访问模式

最简单、最干净的方法是使用 Oliver Steele 的嵌套对象访问模式

const name = ((user || {}).personalInfo || {}).name;

使用此表示法,您将永远不会遇到

Cannot read property 'name' of undefined 。

您基本上检查用户是否存在,如果不存在,则动态创建一个空对象。这样,下一级键将始终从存在的对象或空对象访问,但永远不会从未定义的对象访问。

2. 使用数组Reduce 访问嵌套对象

为了能够访问嵌套数组,您可以编写自己的数组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.

还有一个出色的类型处理最小库 typy 可以为您完成所有这一切。

Just in case, anyone's visiting this question in 2017 or later and looking for an easy-to-remember way, here's an elaborate blog post on Accessing Nested Objects in JavaScript without being bamboozled by

Cannot read property 'foo' of undefined error

1. Oliver Steele's nested object access pattern

The easiest and the cleanest way is to use Oliver Steele's nested object access pattern

const name = ((user || {}).personalInfo || {}).name;

With this notation, you'll never run into

Cannot read property 'name' of undefined.

You basically check if user exists, if not, you create an empty object on the fly. This way, the next level key will always be accessed from an object that exists or an empty object, but never from undefined.

2. Access Nested Objects Using Array Reduce

To be able to access nested arrays, you can write your own array 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.

There is also an excellent type handling minimal library typy that does all this for you.

猥︴琐丶欲为 2025-01-19 06:52:46

如果您愿意包含一个库,那么使用 JSONPath 将是最灵活的解决方案之一:
https://github.com/s3u/JSONPath (节点和浏览器)

对于您的用例,json 路径将是:

$..items[1].name

所以:

var secondName = jsonPath.eval(data, "$..items[1].name");

Using JSONPath would be one of the most flexible solutions if you are willing to include a library:
https://github.com/s3u/JSONPath (node and browser)

For your use case the json path would be:

$..items[1].name

so:

var secondName = jsonPath.eval(data, "$..items[1].name");
一场春暖 2025-01-19 06:52:46

我更喜欢 JQuery。它更干净且易于阅读。

$.each($.parseJSON(data), function (key, value) {
  alert(value.<propertyname>);
});

I prefer JQuery. It's cleaner and easy to read.

$.each($.parseJSON(data), function (key, value) {
  alert(value.<propertyname>);
});
秋日私语 2025-01-19 06:52:46

如果您正在寻找一个或多个满足特定条件的对象,您可以使用 query-js< /a>

//will return all elements with an id larger than 1
data.items.where(function(e){return e.id > 1;});
//will return the first element with an id larger than 1
data.items.first(function(e){return e.id > 1;});
//will return the first element with an id larger than 1 
//or the second argument if non are found
data.items.first(function(e){return e.id > 1;},{id:-1,name:""});

还有一个 singlesingleOrDefault,它们的工作方式分别与 firstfirstOrDefault 类似。唯一的区别是,如果找到多于一个匹配项,它们就会抛出异常。

要进一步解释 query-js,您可以从这个 post< /a>

If you are looking for one or more objects that meets certain criteria you have a few options using query-js

//will return all elements with an id larger than 1
data.items.where(function(e){return e.id > 1;});
//will return the first element with an id larger than 1
data.items.first(function(e){return e.id > 1;});
//will return the first element with an id larger than 1 
//or the second argument if non are found
data.items.first(function(e){return e.id > 1;},{id:-1,name:""});

There's also a single and a singleOrDefault they work much like firstand firstOrDefaultrespectively. The only difference is that they will throw if more than one match is found.

for further explanation of query-js you can start with this post

九八野马 2025-01-19 06:52:46

Underscore js Way

这是一个 JavaScript 库,它提供了一整套有用的函数式编程帮助程序,而无需扩展任何内置对象。

解决方案:

var data = {
  code: 42,
  items: [{
    id: 1,
    name: 'foo'
  }, {
    id: 2,
    name: 'bar'
  }]
};

var item = _.findWhere(data.items, {
  id: 2
});
if (!_.isUndefined(item)) {
  console.log('NAME =>', item.name);
}

//using find - 

var item = _.find(data.items, function(item) {
  return item.id === 2;
});

if (!_.isUndefined(item)) {
  console.log('NAME =>', item.name);
}

The Underscore js Way

Which is a JavaScript library that provides a whole mess of useful functional programming helpers without extending any built-in objects.

Solution:

var data = {
  code: 42,
  items: [{
    id: 1,
    name: 'foo'
  }, {
    id: 2,
    name: 'bar'
  }]
};

var item = _.findWhere(data.items, {
  id: 2
});
if (!_.isUndefined(item)) {
  console.log('NAME =>', item.name);
}

//using find - 

var item = _.find(data.items, function(item) {
  return item.id === 2;
});

if (!_.isUndefined(item)) {
  console.log('NAME =>', item.name);
}
行雁书 2025-01-19 06:52:46

老问题,但没有人提到 lodash (只是下划线)。

如果您已经在项目中使用了 lodash,我认为在复杂的示例中可以采用一种优雅的方式来实现此目的:

Opt 1

_.get(response, ['output', 'fund', 'data', '0', 'children', '0', 'group', 'myValue'], '')

与:

Opt 2

response.output.fund.data[0].children[0].group.myValue

相同第二个选项是,在选项 1 中,如果路径中缺少(未定义)属性之一,则不会收到错误,它会返回第三个参数。

对于数组过滤器,lodash 有 _.find() 但我宁愿使用常规的 filter()。但我仍然认为上述方法 _.get() 在处理非常复杂的数据时非常有用。我过去遇到过非常复杂的 API,但它很方便!

我希望它对那些正在寻找操作标题所暗示的真正复杂数据的选项的人有用。

Old question but as nobody mentioned lodash (just underscore).

In case you are already using lodash in your project, I think an elegant way to do this in a complex example:

Opt 1

_.get(response, ['output', 'fund', 'data', '0', 'children', '0', 'group', 'myValue'], '')

same as:

Opt 2

response.output.fund.data[0].children[0].group.myValue

The difference between the first and second option is that in the Opt 1 if you have one of the properties missing (undefined) in the path you don't get an error, it returns you the third parameter.

For array filter lodash has _.find() but I'd rather use the regular filter(). But I still think the above method _.get() is super useful when working with really complex data. I faced in the past really complex APIs and it was handy!

I hope it can be useful for who's looking for options to manipulate really complex data which the title implies.

芯好空 2025-01-19 06:52:46

我不认为提问者只关心一级嵌套对象,因此我提供以下演示来演示如何访问深度嵌套的 json 对象的节点。好吧,让我们找到 id 为“5”的节点。

var data = {
  code: 42,
  items: [{
    id: 1,
    name: 'aaa',
    items: [{
        id: 3,
        name: 'ccc'
      }, {
        id: 4,
        name: 'ddd'
      }]
    }, {
    id: 2,
    name: 'bbb',
    items: [{
        id: 5,
        name: 'eee'
      }, {
        id: 6,
        name: 'fff'
      }]
    }]
};

var jsonloop = new JSONLoop(data, 'id', 'items');

jsonloop.findNodeById(data, 5, function(err, node) {
  if (err) {
    document.write(err);
  } else {
    document.write(JSON.stringify(node, null, 2));
  }
});
<script src="https://rawgit.com/dabeng/JSON-Loop/master/JSONLoop.js"></script>

I don't think questioner just only concern one level nested object, so I present the following demo to demonstrate how to access the node of deeply nested json object. All right, let's find the node with id '5'.

var data = {
  code: 42,
  items: [{
    id: 1,
    name: 'aaa',
    items: [{
        id: 3,
        name: 'ccc'
      }, {
        id: 4,
        name: 'ddd'
      }]
    }, {
    id: 2,
    name: 'bbb',
    items: [{
        id: 5,
        name: 'eee'
      }, {
        id: 6,
        name: 'fff'
      }]
    }]
};

var jsonloop = new JSONLoop(data, 'id', 'items');

jsonloop.findNodeById(data, 5, function(err, node) {
  if (err) {
    document.write(err);
  } else {
    document.write(JSON.stringify(node, null, 2));
  }
});
<script src="https://rawgit.com/dabeng/JSON-Loop/master/JSONLoop.js"></script>

不交电费瞎发啥光 2025-01-19 06:52:46

在 2020 年,您可以使用 @babel/plugin-proposal-optical-chaining 它可以非常轻松地访问对象中的嵌套值。

 const obj = {
 foo: {
   bar: {
     baz: class {
   },
  },
 },
};

const baz = new obj?.foo?.bar?.baz(); // baz instance

const safe = new obj?.qux?.baz(); // undefined
const safe2 = new obj?.foo.bar.qux?.(); // undefined

https://babeljs.io/docs/en/babel-plugin-proposal -可选链

https://github.com/tc39/proposal-optional-chaining

In 2020, you can use @babel/plugin-proposal-optional-chaining it is very easy to access nested values in an object.

 const obj = {
 foo: {
   bar: {
     baz: class {
   },
  },
 },
};

const baz = new obj?.foo?.bar?.baz(); // baz instance

const safe = new obj?.qux?.baz(); // undefined
const safe2 = new obj?.foo.bar.qux?.(); // undefined

https://babeljs.io/docs/en/babel-plugin-proposal-optional-chaining

https://github.com/tc39/proposal-optional-chaining

寻梦旅人 2025-01-19 06:52:46

动态方法

在下面的 deep(data,key) 函数中,您可以使用任意 key 字符串 - 在您的情况下 items[1].name (您可以在任何级别使用数组表示法 [i]) - 如果 key 无效,则返回 undefined 。

let deep = (o,k) => k.split('.').reduce((a,c,i) => {
    let m=c.match(/(.*?)\[(\d*)\]/);
    if(m && a!=null && a[m[1]]!=null) return a[m[1]][+m[2]];
    return a==null ? a: a[c];
},o);

// TEST

let key = 'items[1].name' // arbitrary deep-key

let data = {
    code: 42,
    items: [{ id: 11, name: 'foo'}, { id: 22, name: 'bar'},]
};

console.log( key,'=', deep(data,key) );

Dynamic approach

In below deep(data,key) function, you can use arbitrary key string - in your case items[1].name (you can use array notation [i] at any level) - if key is invalid then undefined is return.

let deep = (o,k) => k.split('.').reduce((a,c,i) => {
    let m=c.match(/(.*?)\[(\d*)\]/);
    if(m && a!=null && a[m[1]]!=null) return a[m[1]][+m[2]];
    return a==null ? a: a[c];
},o);

// TEST

let key = 'items[1].name' // arbitrary deep-key

let data = {
    code: 42,
    items: [{ id: 11, name: 'foo'}, { id: 22, name: 'bar'},]
};

console.log( key,'=', deep(data,key) );

蹲在坟头点根烟 2025-01-19 06:52:46

jQuery 的 grep 函数可让您过滤数组:

var data = {
    code: 42,
    items: [{
        id: 1,
        name: 'foo'
    }, {
        id: 2,
        name: 'bar'
    }]
};

$.grep(data.items, function(item) {
    if (item.id === 2) {
        console.log(item.id); //console id of item
        console.log(item.name); //console name of item
        console.log(item); //console item object
        return item; //returns item object
    }

});
// Object {id: 2, name: "bar"}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

jQuery's grep function lets you filter through an array:

var data = {
    code: 42,
    items: [{
        id: 1,
        name: 'foo'
    }, {
        id: 2,
        name: 'bar'
    }]
};

$.grep(data.items, function(item) {
    if (item.id === 2) {
        console.log(item.id); //console id of item
        console.log(item.name); //console name of item
        console.log(item); //console item object
        return item; //returns item object
    }

});
// Object {id: 2, name: "bar"}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

终陌 2025-01-19 06:52:46

您可以使用语法 jsonObject.key 来访问该值。如果您想访问数组中的值,则可以使用语法 jsonObjectArray[index].key

以下是访问各种值的代码示例,以便您了解。

var data = {
    code: 42,
    items: [{
        id: 1,
        name: 'foo'
    }, {
        id: 2,
        name: 'bar'
    }]
};

// if you want 'bar'
console.log(data.items[1].name);

// if you want array of item names
console.log(data.items.map(x => x.name));

// get the id of the item where name = 'bar'
console.log(data.items.filter(x => (x.name == "bar") ? x.id : null)[0].id);

You can use the syntax jsonObject.key to access the the value. And if you want access a value from an array, then you can use the syntax jsonObjectArray[index].key.

Here are the code examples to access various values to give you the idea.

var data = {
    code: 42,
    items: [{
        id: 1,
        name: 'foo'
    }, {
        id: 2,
        name: 'bar'
    }]
};

// if you want 'bar'
console.log(data.items[1].name);

// if you want array of item names
console.log(data.items.map(x => x.name));

// get the id of the item where name = 'bar'
console.log(data.items.filter(x => (x.name == "bar") ? x.id : null)[0].id);

半仙 2025-01-19 06:52:46

我就是这样做的。

 let groups = [
        {
            id:1,
            title:"Group 1",
            members:[
                {
                    id:1,
                    name:"Aftab",
                    battry:'10%'
                },
                {
                    id:2,
                    name:"Jamal",
                },
                {
                    id:3,
                    name:"Hamid",
                },
                {
                    id:4,
                    name:"Aqeel",
                },
            ]
        },
        {
            id:2,
            title:"Group 2",
            members:[
                {
                    id:1,
                    name:"Aftab",
                    battry:'10%'
                },
                {
                    id:2,
                    name:"Jamal",
                    battry:'10%'
                },
                {
                    id:3,
                    name:"Hamid",
                },
               
            ]
        },
        {
            id:3,
            title:"Group 3",
            members:[
                {
                    id:1,
                    name:"Aftab",
                    battry:'10%'
                },
                
                {
                    id:3,
                    name:"Hamid",
                },
                {
                    id:4,
                    name:"Aqeel",
                },
            ]
        }
    ]
    
    groups.map((item) => {
      //  if(item.id == 2){
        item.members.map((element) => {
             if(element.id == 1){
                 element.battry="20%"
             }
         })
        //}
    })
    
    groups.forEach((item) => {
        item.members.forEach((item) => {
            console.log(item)
    })
    })

this is how i have done this.

 let groups = [
        {
            id:1,
            title:"Group 1",
            members:[
                {
                    id:1,
                    name:"Aftab",
                    battry:'10%'
                },
                {
                    id:2,
                    name:"Jamal",
                },
                {
                    id:3,
                    name:"Hamid",
                },
                {
                    id:4,
                    name:"Aqeel",
                },
            ]
        },
        {
            id:2,
            title:"Group 2",
            members:[
                {
                    id:1,
                    name:"Aftab",
                    battry:'10%'
                },
                {
                    id:2,
                    name:"Jamal",
                    battry:'10%'
                },
                {
                    id:3,
                    name:"Hamid",
                },
               
            ]
        },
        {
            id:3,
            title:"Group 3",
            members:[
                {
                    id:1,
                    name:"Aftab",
                    battry:'10%'
                },
                
                {
                    id:3,
                    name:"Hamid",
                },
                {
                    id:4,
                    name:"Aqeel",
                },
            ]
        }
    ]
    
    groups.map((item) => {
      //  if(item.id == 2){
        item.members.map((element) => {
             if(element.id == 1){
                 element.battry="20%"
             }
         })
        //}
    })
    
    groups.forEach((item) => {
        item.members.forEach((item) => {
            console.log(item)
    })
    })
染柒℉ 2025-01-19 06:52:46

如果您尝试在 JSON 字符串中查找路径,可以将数据转储到工具中来确定路径。

当您将鼠标悬停在嵌套 JS 对象结构中的属性路径上时,Chrome 开发人员控制台会显示属性路径,如有必要,可以使用 JSON.parse(json) 从 JSON 解析属性路径:

chrome 控制台悬停对象键会显示路径得到将鼠标悬停在此处

您还可以将路径复制到剪贴板:

chrome 控制台即将使用节点上的上下文菜单将对象的属性路径复制到剪贴板

一旦剪贴板上有了路径,你通常会想要迭代数组通过用循环替换 [0] 等偏移索引器。然后,您可以在其位置使用循环索引 [i],或使用 forEach 样式函数来替换整个属性和索引。

另一个工具是 https://jsonpathfinder.com,您可以在其中单击 GUI 元素。它会像 Chrome 一样生成元素路径的 JS 语法。

我编写了一个简单的工具,您可以在此处运行,或者在 https://ggorlen.github.io/json -潜水/。将 JSON 字符串粘贴到文本区域,然后单击节点将其路径复制到剪贴板。它可以选择生成带有括号而不是点的 Python/PHP 样式索引。

/* 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>

未缩小(也可在 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>

这并不是要替代学习如何钓鱼,但一旦您知道了,就可以节省时间。

If you're trying to find a path in a JSON string, you can dump your data into a tool to determine the path for you.

The Chrome developer console shows property paths when you hover over them in a nested JS object structure, which can be parsed from JSON using JSON.parse(json) if necessary:

chrome console hovering an object key shows the path to get there on hover

You can also copy the path to the clipboard:

chrome console about to copy property path for object to clipboard using the context menu on a node

Once you have a path on the clipboard, you will typically want to iterate arrays by replacing the offset indexers like [0] with a loop. You can then use the loop index [i] in its place, or use a forEach style function to replace the whole property and index.

Another tool is https://jsonpathfinder.com where you can click on the GUI elements. It'll generate the JS syntax for the path to the element like Chrome.

I wrote a simple tool you can run here, or at https://ggorlen.github.io/json-dive/. Paste your JSON string into the textarea, then click the node to copy its path to your clipboard. It has an option to generate Python/PHP style indexes with brackets rather than dots.

/* 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 (also available on 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>

This isn't intended as a substitute for learning how to fish but can save time once you do know.

偏闹i 2025-01-19 06:52:46
// const path = 'info.value[0].item'
// const obj = { info: { value: [ { item: 'it works!' } ], randominfo: 3 }  }
// getValue(path, obj)

export const getValue = ( path , obj) => {
  const newPath = path.replace(/\]/g, "")
  const arrayPath = newPath.split(/[\[\.]+/) || newPath;

  const final = arrayPath.reduce( (obj, k) => obj ?  obj[k] : obj, obj)
  return final;
}
// const path = 'info.value[0].item'
// const obj = { info: { value: [ { item: 'it works!' } ], randominfo: 3 }  }
// getValue(path, obj)

export const getValue = ( path , obj) => {
  const newPath = path.replace(/\]/g, "")
  const arrayPath = newPath.split(/[\[\.]+/) || newPath;

  const final = arrayPath.reduce( (obj, k) => obj ?  obj[k] : obj, obj)
  return final;
}
兔小萌 2025-01-19 06:52:46

这是使用 object-scan 的答案。

当访问单个条目时,这个答案并没有真正比普通的 javascript 提供太多好处。然而,同时与多个字段交互,这个答案可以更高效。

这是与单个字段交互的方式

// const objectScan = require('object-scan');

const data = { code: 42, items: [{ id: 1, name: 'foo' }, { id: 2, name: 'bar' }] };

const get = (haystack, needle) => objectScan([needle], {
  abort: true,
  rtn: 'value'
})(haystack);

const set = (haystack, needle, value) => objectScan([needle], {
  abort: true,
  rtn: 'bool',
  filterFn: ({ parent, property }) => {
    parent[property] = value;
    return true;
  }
})(haystack);

console.log(get(data, 'items[1].name'));
// => bar

console.log(set(data, 'items[1].name', 'foo2'));
// => true
console.log(data);
// => { code: 42, items: [ { id: 1, name: 'foo' }, { id: 2, name: 'foo2' } ] }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/[email protected]"></script>

免责声明:我是 object-scan 的作者

这是同时与多个字段交互的方法

// const objectScan = require('object-scan');

const data = { code: 42, items: [{ id: 1, name: 'foo' }, { id: 2, name: 'bar' }] };

const get = (haystack, ...needles) => objectScan(needles, {
  joined: true,
  rtn: 'entry'
})(haystack);

const set = (haystack, actions) => objectScan(Object.keys(actions), {
  rtn: 'count',
  filterFn: ({ matchedBy, parent, property }) => {
    matchedBy.forEach((m) => {
      parent[property] = actions[m];
    })
    return true;
  }
})(haystack);

console.log(get(data, 'items[0].name', 'items[1].name'));
// => [ [ 'items[1].name', 'bar' ], [ 'items[0].name', 'foo' ] ]

console.log(set(data, {
  'items[0].name': 'foo1',
  'items[1].name': 'foo2'
}));
// => 2
console.log(data);
// => { code: 42, items: [ { id: 1, name: 'foo1' }, { id: 2, name: 'foo2' } ] }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/[email protected]"></script>

免责声明:我是 object-scan 的作者


这是如何通过 id 搜索在深层嵌套对象中找到实体的方法(如评论中所述)

// const objectScan = require('object-scan');

const myData = { code: 42, items: [{ id: 1, name: 'aaa', items: [{ id: 3, name: 'ccc' }, { id: 4, name: 'ddd' }] }, { id: 2, name: 'bbb', items: [{ id: 5, name: 'eee' }, { id: 6, name: 'fff' }] }] };

const findItemById = (haystack, id) => objectScan(['**(^items$).id'], {
  abort: true,
  useArraySelector: false,
  rtn: 'parent',
  filterFn: ({ value }) => value === id
})(haystack);

console.log(findItemById(myData, 5));
// => { id: 5, name: 'eee' }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/[email protected]"></script>

免责声明:我是 object-scan 的作者

Here is an answer using object-scan.

When accessing a single entry, this answer doesn't really provide much benefit over vanilla javascript. However interacting with multiple fields at the same time this answer can be more performant.

Here is how you could interact with a single field

// const objectScan = require('object-scan');

const data = { code: 42, items: [{ id: 1, name: 'foo' }, { id: 2, name: 'bar' }] };

const get = (haystack, needle) => objectScan([needle], {
  abort: true,
  rtn: 'value'
})(haystack);

const set = (haystack, needle, value) => objectScan([needle], {
  abort: true,
  rtn: 'bool',
  filterFn: ({ parent, property }) => {
    parent[property] = value;
    return true;
  }
})(haystack);

console.log(get(data, 'items[1].name'));
// => bar

console.log(set(data, 'items[1].name', 'foo2'));
// => true
console.log(data);
// => { code: 42, items: [ { id: 1, name: 'foo' }, { id: 2, name: 'foo2' } ] }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/[email protected]"></script>

Disclaimer: I'm the author of object-scan

and here is how you could interact with multiple fields at the same time

// const objectScan = require('object-scan');

const data = { code: 42, items: [{ id: 1, name: 'foo' }, { id: 2, name: 'bar' }] };

const get = (haystack, ...needles) => objectScan(needles, {
  joined: true,
  rtn: 'entry'
})(haystack);

const set = (haystack, actions) => objectScan(Object.keys(actions), {
  rtn: 'count',
  filterFn: ({ matchedBy, parent, property }) => {
    matchedBy.forEach((m) => {
      parent[property] = actions[m];
    })
    return true;
  }
})(haystack);

console.log(get(data, 'items[0].name', 'items[1].name'));
// => [ [ 'items[1].name', 'bar' ], [ 'items[0].name', 'foo' ] ]

console.log(set(data, {
  'items[0].name': 'foo1',
  'items[1].name': 'foo2'
}));
// => 2
console.log(data);
// => { code: 42, items: [ { id: 1, name: 'foo1' }, { id: 2, name: 'foo2' } ] }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/[email protected]"></script>

Disclaimer: I'm the author of object-scan


And here is how one could find an entity in a deeply nested object searching by id (as asked in comment)

// const objectScan = require('object-scan');

const myData = { code: 42, items: [{ id: 1, name: 'aaa', items: [{ id: 3, name: 'ccc' }, { id: 4, name: 'ddd' }] }, { id: 2, name: 'bbb', items: [{ id: 5, name: 'eee' }, { id: 6, name: 'fff' }] }] };

const findItemById = (haystack, id) => objectScan(['**(^items$).id'], {
  abort: true,
  useArraySelector: false,
  rtn: 'parent',
  filterFn: ({ value }) => value === id
})(haystack);

console.log(findItemById(myData, 5));
// => { id: 5, name: 'eee' }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/[email protected]"></script>

Disclaimer: I'm the author of object-scan

梦在深巷 2025-01-19 06:52:46

你需要做的非常简单,可以通过递归来实现:

const json_object = {
        "item1":{
            "name": "apple",
            "value": 2,
        },
        "item2":{
            "name": "pear",
            "value": 4,
        },
        "item3":{
            "name": "mango",
            "value": 3,
            "prices": {
                "1": "9$",
                "2": "59$",
                "3": "1$"
            }
        }
    }
    
    function walkJson(json_object){
        for(obj in json_object){
            if(typeof json_object[obj] === 'string'){
                console.log(`${obj}=>${json_object[obj]}`);
            }else{
                console.log(`${obj}=>${json_object[obj]}`);
                walkJson(json_object[obj]);
            }
        }           
    }
    
    walkJson(json_object);

what you need to do is really simple and it can be achieved trough recursivity:

const json_object = {
        "item1":{
            "name": "apple",
            "value": 2,
        },
        "item2":{
            "name": "pear",
            "value": 4,
        },
        "item3":{
            "name": "mango",
            "value": 3,
            "prices": {
                "1": "9
quot;,
                "2": "59
quot;,
                "3": "1
quot;
            }
        }
    }
    
    function walkJson(json_object){
        for(obj in json_object){
            if(typeof json_object[obj] === 'string'){
                console.log(`${obj}=>${json_object[obj]}`);
            }else{
                console.log(`${obj}=>${json_object[obj]}`);
                walkJson(json_object[obj]);
            }
        }           
    }
    
    walkJson(json_object);
燃情 2025-01-19 06:52:46

一种解析任意 JSON 树的 Pythonic、递归和函数式方法:

handlers = {
    list:  iterate,
    dict:  delve,
    str:   emit_li,
    float: emit_li,
}

def emit_li(stuff, strong=False):
    emission = '<li><strong>%s</strong></li>' if strong else '<li>%s</li>'
    print(emission % stuff)

def iterate(a_list):
    print('<ul>')
    map(unravel, a_list)
    print('</ul>')

def delve(a_dict):
    print('<ul>')
    for key, value in a_dict.items():
        emit_li(key, strong=True)
        unravel(value)
    print('</ul>')

def unravel(structure):
    h = handlers[type(structure)]
    return h(structure)

unravel(data)

其中 data 是一个 Python 列表(从 JSON 文本字符串解析):

data = [
    {'data': {'customKey1': 'customValue1',
           'customKey2': {'customSubKey1': {'customSubSubKey1': 'keyvalue'}}},
  'geometry': {'location': {'lat': 37.3860517, 'lng': -122.0838511},
               'viewport': {'northeast': {'lat': 37.4508789,
                                          'lng': -122.0446721},
                            'southwest': {'lat': 37.3567599,
                                          'lng': -122.1178619}}},
  'name': 'Mountain View',
  'scope': 'GOOGLE',
  'types': ['locality', 'political']}
]

A pythonic, recursive and functional approach to unravel arbitrary JSON trees:

handlers = {
    list:  iterate,
    dict:  delve,
    str:   emit_li,
    float: emit_li,
}

def emit_li(stuff, strong=False):
    emission = '<li><strong>%s</strong></li>' if strong else '<li>%s</li>'
    print(emission % stuff)

def iterate(a_list):
    print('<ul>')
    map(unravel, a_list)
    print('</ul>')

def delve(a_dict):
    print('<ul>')
    for key, value in a_dict.items():
        emit_li(key, strong=True)
        unravel(value)
    print('</ul>')

def unravel(structure):
    h = handlers[type(structure)]
    return h(structure)

unravel(data)

where data is a python list (parsed from a JSON text string):

data = [
    {'data': {'customKey1': 'customValue1',
           'customKey2': {'customSubKey1': {'customSubSubKey1': 'keyvalue'}}},
  'geometry': {'location': {'lat': 37.3860517, 'lng': -122.0838511},
               'viewport': {'northeast': {'lat': 37.4508789,
                                          'lng': -122.0446721},
                            'southwest': {'lat': 37.3567599,
                                          'lng': -122.1178619}}},
  'name': 'Mountain View',
  'scope': 'GOOGLE',
  'types': ['locality', 'political']}
]
ま昔日黯然 2025-01-19 06:52:46

我的 stringdata 来自 PHP 文件,但我仍然在 var 中指出。当我直接将 json 放入 obj 时,它不会显示任何内容,这就是为什么我将 json 文件设置为

var obj=JSON.parse(stringdata);
所以之后我得到message obj并显示在警报框中,然后我得到data,它是json数组并存储在一个变量ArrObj中,然后我读该数组的第一个对象,其键值如下 ArrObj[0].id

    var stringdata='{"success": true,"message": "working","data":[{"id":1,"name": "foo"}]}';

            var obj=JSON.parse(stringdata);
            var key = "message";
            alert(obj[key]);
            var keyobj = "data";
            var ArrObj =obj[keyobj];

            alert(ArrObj[0].id);
            

My stringdata is coming from PHP file but still, I indicate here in var. When i directly take my json into obj it will nothing show thats why i put my json file as

var obj=JSON.parse(stringdata);
so after that i get message obj and show in alert box then I get data which is json array and store in one varible ArrObj then i read first object of that array with key value like this ArrObj[0].id

    var stringdata='{"success": true,"message": "working","data":[{"id":1,"name": "foo"}]}';

            var obj=JSON.parse(stringdata);
            var key = "message";
            alert(obj[key]);
            var keyobj = "data";
            var ArrObj =obj[keyobj];

            alert(ArrObj[0].id);
            
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文