Làm cách nào tôi có thể truy cập và xử lý các đối tượng, mảng hoặc JSON lồng nhau?


875

Tôi có một cấu trúc dữ liệu lồng nhau chứa các đối tượng và mảng. Làm cách nào tôi có thể trích xuất thông tin, tức là truy cập vào một giá trị cụ thể hoặc nhiều giá trị (hoặc khóa)?

Ví dụ:

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

Làm thế nào tôi có thể truy cập vào namemục thứ hai items?


22
@Marcel: Nó phải được đọc là "Tôi có cấu trúc dữ liệu lồng nhau hoặc JSON, làm cách nào tôi có thể truy cập một giá trị cụ thể?". Tôi biết sự khác biệt, nhưng nhiều người không và có thể đang tìm kiếm "JSON" thay vì "đối tượng". Nhiều câu hỏi thực sự có dạng "làm thế nào tôi có thể truy cập X trong JSON này". Nơi duy nhất tôi đề cập đến JSON trong câu trả lời của mình là nơi tôi giải thích nó là gì. Nếu bạn có một gợi ý làm thế nào để truyền đạt điều này theo cách tốt hơn, tôi sẽ nghe thấy.
Felix Kling

bản sao có thể có của JSON find trong JavaScript
Travis J

Câu trả lời:


1159

Sơ bộ

JavaScript chỉ có một loại dữ liệu có thể chứa nhiều giá trị: Object . Một mảng là một dạng đối tượng đặc biệt.

(Đồng bằng) Các đối tượng có dạng

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

Mảng có hình thức

[value, value, ...]

Cả mảng và đối tượng phơi bày một key -> valuecấu trúc. Các khóa trong một mảng phải là số, trong khi bất kỳ chuỗi nào cũng có thể được sử dụng làm khóa trong các đối tượng. Các cặp khóa-giá trị cũng được gọi là "thuộc tính" .

Các thuộc tính có thể được truy cập bằng cách sử dụng ký hiệu chấm

const value = obj.someProperty;

hoặc ký hiệu ngoặc , nếu tên thuộc tính sẽ không phải là tên định danh JavaScript hợp lệ [spec] hoặc tên là giá trị của biến:

// 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];

Vì lý do đó, các phần tử mảng chỉ có thể được truy cập bằng cách sử dụng ký hiệu ngoặc:

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

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

Đợi ... còn JSON thì sao?

JSON là một biểu diễn văn bản của dữ liệu, giống như XML, YAML, CSV và các dữ liệu khác. Để làm việc với dữ liệu đó, trước tiên, nó phải được chuyển đổi thành các loại dữ liệu JavaScript, tức là mảng và đối tượng (và cách làm việc với những dữ liệu vừa được giải thích). Làm cách nào để phân tích JSON được giải thích trong câu hỏi Phân tích JSON trong JavaScript? .

Đọc thêm tài liệu

Cách truy cập mảng và đối tượng là kiến ​​thức cơ bản về JavaScript và do đó, nên đọc Hướng dẫn JavaScript MDN , đặc biệt là các phần



Truy cập cấu trúc dữ liệu lồng nhau

Cấu trúc dữ liệu lồng nhau là một mảng hoặc đối tượng tham chiếu đến các mảng hoặc đối tượng khác, tức là các giá trị của nó là mảng hoặc đối tượng. Các cấu trúc như vậy có thể được truy cập bằng cách áp dụng liên tục dấu chấm hoặc dấu ngoặc.

Đây là một ví dụ:

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

Giả sử chúng ta muốn truy cập vào namemục thứ hai.

Đây là cách chúng ta có thể làm từng bước một:

Như chúng ta có thể thấy datalà một đối tượng, do đó chúng ta có thể truy cập các thuộc tính của nó bằng cách sử dụng ký hiệu chấm. Các itemstài sản được truy cập như sau:

data.items

Giá trị là một mảng, để truy cập phần tử thứ hai của nó, chúng ta phải sử dụng ký hiệu ngoặc:

data.items[1]

Giá trị này là một đối tượng và chúng tôi sử dụng ký hiệu chấm một lần nữa để truy cập vào thuộc nametính. Vì vậy, cuối cùng chúng tôi nhận được:

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

Ngoài ra, chúng tôi có thể đã sử dụng ký hiệu dấu ngoặc cho bất kỳ thuộc tính nào, đặc biệt nếu tên chứa các ký tự sẽ làm cho nó không hợp lệ cho việc sử dụng ký hiệu dấu chấm:

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

Tôi đang cố gắng truy cập vào một tài sản nhưng tôi chỉ nhận undefinedlại?

Hầu hết thời gian khi bạn nhận được undefined, đối tượng / mảng đơn giản là không có thuộc tính với tên đó.

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

Sử dụng console.loghoặc console.dirvà kiểm tra cấu trúc của đối tượng / mảng. Thuộc tính bạn đang cố truy cập có thể thực sự được xác định trên một đối tượng / mảng lồng nhau.

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

Điều gì xảy ra nếu tên tài sản là động và tôi không biết chúng trước?

Nếu tên thuộc tính không xác định hoặc chúng tôi muốn truy cập tất cả các thuộc tính của một đối tượng / thành phần của mảng, chúng ta có thể sử dụng vòng lặp for...in [MDN] cho các đối tượng và vòng lặp for [MDN] cho các mảng để lặp lại trên tất cả các thuộc tính / thành phần.

Các đối tượng

Để lặp lại tất cả các thuộc tính của data, chúng ta có thể lặp lại đối tượng như vậy:

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
}

Tùy thuộc vào nơi đối tượng đến từ (và những gì bạn muốn làm), bạn có thể phải kiểm tra trong mỗi lần lặp xem liệu tài sản đó có thực sự là một tài sản của đối tượng hay đó là một tài sản được thừa kế. Bạn có thể làm điều này với Object#hasOwnProperty [MDN] .

Thay thế cho for...inbằng hasOwnProperty, bạn có thể sử dụng Object.keys [MDN] để lấy một mảng các tên thuộc tính :

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

Mảng

Để lặp lại tất cả các phần tử của data.items mảng , chúng tôi sử dụng một forvòng lặp:

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`.
}

Người ta cũng có thể sử dụng for...inđể lặp lại trên các mảng, nhưng có những lý do tại sao điều này nên tránh: Tại sao 'for (var item in list)' với các mảng được coi là thực hành xấu trong JavaScript? .

Với sự hỗ trợ trình duyệt ngày càng tăng của ECMAScript 5, phương thức mảng forEach [MDN] cũng trở thành một thay thế thú vị:

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)
}); 

Trong các môi trường hỗ trợ ES2015 (ES6), bạn cũng có thể sử dụng vòng lặp [MDN] , nó không chỉ hoạt động cho các mảng, mà còn cho bất kỳ lần lặp nào :for...of

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

Trong mỗi lần lặp, for...oftrực tiếp cung cấp cho chúng ta phần tử tiếp theo của lần lặp, không có "chỉ mục" để truy cập hoặc sử dụng.


Điều gì xảy ra nếu tôi không biết "độ sâu" của cấu trúc dữ liệu?

Ngoài các khóa không xác định, "độ sâu" của cấu trúc dữ liệu (nghĩa là có bao nhiêu đối tượng lồng nhau), có thể cũng không xác định được. Làm thế nào để truy cập các thuộc tính lồng nhau sâu thường phụ thuộc vào cấu trúc dữ liệu chính xác.

Nhưng nếu cấu trúc dữ liệu chứa các mẫu lặp lại, ví dụ: biểu diễn của cây nhị phân, giải pháp thường bao gồm để truy cập đệ quy [Wikipedia] mỗi cấp của cấu trúc dữ liệu.

Dưới đây là một ví dụ để có được nút lá đầu tiên của cây nhị phân:

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);

Một cách chung hơn để truy cập cấu trúc dữ liệu lồng nhau với các khóa và độ sâu không xác định là kiểm tra loại giá trị và hành động tương ứng.

Dưới đây là một ví dụ bổ sung tất cả các giá trị nguyên thủy bên trong cấu trúc dữ liệu lồng nhau vào một mảng (giả sử nó không chứa bất kỳ hàm nào). Nếu chúng ta gặp một đối tượng (hoặc mảng), chúng ta chỉ cần gọi toArraylại vào giá trị đó (cuộc gọi đệ quy).

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;
}



Người giúp việc

Do cấu trúc của một đối tượng hoặc mảng phức tạp không nhất thiết phải rõ ràng, chúng ta có thể kiểm tra giá trị ở mỗi bước để quyết định cách di chuyển xa hơn. console.log [MDN]console.dir [MDN] giúp chúng tôi thực hiện việc này. Ví dụ: (đầu ra của bảng điều khiển Chrome):

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

Ở đây chúng ta thấy rằng đó data.itemslà một mảng có hai phần tử là cả hai đối tượng. Trong bảng điều khiển Chrome, các đối tượng thậm chí có thể được mở rộng và kiểm tra ngay lập tức.

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

Điều này cho chúng ta biết đó data.items[1]là một đối tượng và sau khi mở rộng nó, chúng ta thấy rằng nó có ba thuộc tính id, name__proto__. Cái sau là một thuộc tính nội bộ được sử dụng cho chuỗi nguyên mẫu của đối tượng. Chuỗi nguyên mẫu và kế thừa nằm ngoài phạm vi cho câu trả lời này, mặc dù.


3
Một số điều được liên kết ở đây thực sự là hỏi làm thế nào để làm điều này trong jQuery, để công bằng thì đơn giản hóa 1 hoặc 2 điều ở đây. Không chắc chắn nên làm điều này nhiều hơn một câu hay trả lời riêng - những điều cơ bản được đề cập ở đây về đối tượng mà một mảng thường là những gì thực sự được hỏi ....
Chris Moschini

1
@ felix-kling Một điều ... với các đối tượng lồng nhau, chẳng hạn như let object = {a: 1, b: 2, c: { a: 3, b: 4 }};, điều này trả về một mảng chứa một mảng cho mỗi đối tượng lồng nhau, trong trường hợp này, [ 1, 2, [ 3, 4 ] ]sẽ tốt hơn nếu sử dụng concat trong lệnh gọi đệ quy thay vì đẩy? (yêu cầu kết quả phải có thể thay đổi)
ElFitz

3
Đây là câu trả lời sâu sắc nhất tôi từng thấy trên Stack Overflow - và nó đã trả lời câu hỏi của tôi! Cảm ơn!
William Jones

trang này khiến tôi tìm hiểu sự khác biệt giữa ARRAY và OBJ
4ni5

76

Bạn có thể truy cập nó theo cách này

data.items[1].name

hoặc là

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

Cả hai cách đều như nhau.


Vâng, nhưng bạn không thể thực hiện dữ liệu ["mục"]. 1.name
neaumusic

5
Đầu tiên là trực quan hơn, dễ đọc hơn và ngắn hơn;) Tôi chỉ thích sử dụng cú pháp thuộc tính ngoặc khi tên thuộc tính là biến.
DanteTheSmith

35

Trong trường hợp bạn đang cố gắng truy cập itemtừ cấu trúc ví dụ bằng idhoặc name, mà không biết vị trí của nó trong mảng, cách dễ nhất để làm là sử dụng thư viện 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"}

Từ kinh nghiệm của tôi, việc sử dụng các hàm bậc cao hơn thay vì forhoặc for..invòng lặp dẫn đến mã dễ lý do hơn và do đó dễ bảo trì hơn.

Chỉ cần 2 xu của tôi.


29

Các đối tượng và mảng có rất nhiều phương thức tích hợp có thể giúp bạn xử lý dữ liệu.

Lưu ý: trong nhiều ví dụ tôi đang sử dụng các hàm mũi tên . Chúng tương tự như các biểu thức hàm , nhưng chúng liên kết thisgiá trị theo từ vựng.

Object.keys(), Object.values()(ES 2017) và Object.entries()(ES 2017)

Object.keys()trả về một mảng các khóa của đối tượng, Object.values()trả về một mảng các giá trị của đối tượng và Object.entries()trả về một mảng các khóa của đối tượng và các giá trị tương ứng theo định dạng [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() với một vòng lặp for và hủy bỏ nhiệm vụ

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

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

Nó rất thuận tiện để lặp lại kết quả của Object.entries()một vòng lặp forhủy bài tập .

Vòng lặp for cho phép bạn lặp lại các phần tử mảng. Cú pháp là for (const element of array)(chúng ta có thể thay thế constbằng varhoặc let, nhưng tốt hơn là sử dụng constnếu chúng ta không có ý định sửa đổi element).

Phân công cấu trúc cho phép bạn trích xuất các giá trị từ một mảng hoặc một đối tượng và gán chúng cho các biến. Trong trường hợp này const [key, value]có nghĩa là thay vì gán [key, value]mảng cho element, chúng ta gán phần tử đầu tiên của mảng đó keyvà phần tử thứ hai cho value. Nó tương đương với điều này:

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

Như bạn có thể thấy, việc phá hủy làm cho việc này đơn giản hơn rất nhiều.

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

Các every()phương pháp lợi nhuận truenếu trở về chức năng gọi lại quy định truecho mỗi phần tử của mảng. Các some()phương pháp lợi nhuận truenếu trở về chức năng gọi lại cụ thể truecho một số (ít nhất một) phần tử.

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()Array.prototype.filter()

Các find()phương thức trả về phần tử đầu tiên thỏa mãn hàm gọi lại được cung cấp. Các filter()phương thức trả về một mảng của tất cả các yếu tố đó đáp ứng các chức năng gọi lại cung cấp.

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()

Các map()phương thức trả về một mảng với kết quả của cách gọi một hàm callback được cung cấp trên các phần tử mảng.

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()

Các reduce()phương pháp làm giảm một mảng đến một giá trị duy nhất bằng cách gọi hàm callback được cung cấp với hai yếu tố.

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

Các reduce()phương pháp có một tham số tùy chọn thứ hai, đó là giá trị ban đầu. Điều này hữu ích khi mảng mà bạn gọi reduce()có thể có 0 hoặc một phần tử. Ví dụ: nếu chúng ta muốn tạo một hàm sum()lấy một mảng làm đối số và trả về tổng của tất cả các phần tử, chúng ta có thể viết nó như thế:

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


Đây là câu trả lời yêu thích của tôi. Bạn cũng có thể thêm một ví dụ cho vòng lặp chỉ là dữ liệu lồng nhau, nhưObject.keys(data["items"]).forEach(function(key) { console.log(data["items"][key].id); console.log(data["items"][key].name); });
SilverSurfer

25

Đôi khi, truy cập một đối tượng lồng nhau bằng cách sử dụng một chuỗi có thể được mong muốn. Cách tiếp cận đơn giản là cấp độ đầu tiên, ví dụ

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

Nhưng điều này thường không phải là trường hợp với json phức tạp. Khi json trở nên phức tạp hơn, các phương pháp tìm kiếm giá trị bên trong json cũng trở nên phức tạp. Cách tiếp cận đệ quy để điều hướng json là tốt nhất và cách đệ quy đó được sử dụng sẽ phụ thuộc vào loại dữ liệu được tìm kiếm. Nếu có các tuyên bố có điều kiện liên quan, tìm kiếm json có thể là một công cụ tốt để sử dụng.

Nếu thuộc tính đang được truy cập đã được biết, nhưng đường dẫn phức tạp, ví dụ trong đối tượng này

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

Và bạn biết bạn muốn nhận kết quả đầu tiên của mảng trong đối tượng, có lẽ bạn muốn sử dụng

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

Tuy nhiên, điều đó sẽ gây ra một ngoại lệ vì không có thuộc tính của đối tượng có tên đó. Giải pháp để có thể sử dụng điều này sẽ là làm phẳng khía cạnh cây của đối tượng. Điều này có thể được thực hiện đệ quy.

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;
}

Bây giờ, đối tượng phức tạp có thể được làm phẳng

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

Đây là một jsFiddle Demotrong những phương pháp này đang được sử dụng.


WTH bạn muốn sử dụng obj["arr[0].name"]thay vì obj.arr[0].name? Bạn hầu như không cần / muốn xử lý các đối tượng dẹt trừ việc tuần tự hóa.
Bergi

@Bergi - Tôi thấy câu hỏi này phổ biến, và vì nó đang được sử dụng theo quy tắc, tôi đã đăng một câu trả lời cho phiên bản của nó. Nếu có thể tránh được, việc sử dụng obj.arr [0] .name sẽ nhanh hơn nhiều, nhưng đôi khi mọi người muốn truyền các bộ truy cập chuỗi xung quanh và đây là một ví dụ về việc đó.
Travis J

Urgh. Tuy nhiên, hầu như không có lý do để làm phẳng đối tượng hoàn chỉnh chỉ để sử dụng một đường dẫn chuỗi đơn, bạn có thể chỉ cần phân tích cú pháp đó và thực hiện tra cứu động.
Bergi

14

Câu hỏi này khá cũ, vì vậy như một bản cập nhật đương đại. Với sự khởi đầu của ES2015, có những lựa chọn thay thế để có được dữ liệu bạn yêu cầu. Hiện tại có một tính năng gọi là phá hủy đối tượng để truy cập các đối tượng lồng nhau.

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

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

console.log(secondName);

Ví dụ trên tạo ra một biến được gọi secondNametừ namekhóa từ một mảng được gọi items, cô đơn ,nói bỏ qua đối tượng đầu tiên trong mảng.

Đáng chú ý là nó có thể quá mức cần thiết cho ví dụ này, vì tích lũy mảng đơn giản dễ đọc hơn, nhưng nó có ích khi phá vỡ các đối tượng nói chung.

Đây là phần giới thiệu rất ngắn gọn cho trường hợp sử dụng cụ thể của bạn, việc phá hủy có thể là một cú pháp bất thường để làm quen lúc đầu. Tôi khuyên bạn nên đọc tài liệu Phân công hủy cấu trúc của Mozilla để tìm hiểu thêm.


13

Để truy cập một thuộc tính lồng nhau, bạn cần chỉ định tên của nó và sau đó tìm kiếm thông qua đối tượng.

Nếu bạn đã biết đường dẫn chính xác, thì bạn có thể mã hóa nó trong tập lệnh của mình như sau:

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

những thứ này cũng hoạt động -

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

Khi bạn không biết tên chính xác trước khi sử dụng, hoặc người dùng là người cung cấp tên cho bạn. Sau đó, tự động tìm kiếm thông qua cấu trúc dữ liệu được yêu cầu. Một số gợi ý ở đây rằng tìm kiếm có thể được thực hiện bằng cách sử dụng một forvòng lặp, nhưng có một cách rất đơn giản để đi qua một đường dẫn bằng cách sử dụng 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)

Đường dẫn là một cách để nói: Đầu tiên lấy đối tượng bằng khóa items, điều này xảy ra là một mảng. Sau đó lấy 1phần tử -st (0 mảng chỉ mục). Lần cuối lấy đối tượng có khóa nametrong phần tử mảng đó, đó là chuỗi bar.

Nếu bạn có một con đường rất dài, bạn thậm chí có thể sử dụng String.splitđể làm cho tất cả những điều này dễ dàng hơn -

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

Đây chỉ là JavaScript đơn giản, không sử dụng bất kỳ thư viện bên thứ ba nào như jQuery hoặc lodash.


13
var ourStorage = {


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

hoặc là

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

Về cơ bản, sử dụng một dấu chấm giữa mỗi hậu duệ mở ra bên dưới nó và khi bạn có tên đối tượng được tạo từ hai chuỗi, bạn phải sử dụng ký hiệu ["obj Name"]. Nếu không, chỉ cần một dấu chấm là đủ;

Nguồn: https://learn.freecodecamp.org/javascript-alerskyms-and-data-strucenses/basic-javascript/accessing-nested-objects

để thêm vào điều này, việc truy cập Mảng lồng nhau sẽ xảy ra như vậy:

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"

Nguồn: https://learn.freecodecamp.org/javascript-alerskyms-and-data-strucenses/basic-javascript/accessing-nested-arrays/

Một tài liệu hữu ích khác mô tả tình huống trên: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Basics#Brquet_notation

Truy cập tài sản thông qua dấu chấm đi bộ: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_Accessors#Dot_notation


Mặc dù liên kết này có thể trả lời câu hỏi, tốt hơn là bao gồm các phần thiết yếu của câu trả lời ở đây và cung cấp liên kết để tham khảo. Câu trả lời chỉ liên kết có thể trở nên không hợp lệ nếu trang được liên kết thay đổi. - Từ đánh giá
Robert

1
Tôi đã chỉnh sửa bài viết. Mặc dù mọi người đã nhanh chóng đưa ra đại diện xấu cho nó. Lần tới tôi sẽ không đưa ra câu trả lời.
Johnny

1
@Riddick đừng kiềm chế, chỉ cần đảm bảo rằng bạn không chỉ đăng một liên kết
reggaeg Ức

12

Bạn có thể sử dụng lodash _getchức năng:

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

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

9

Sử dụng JSONPath sẽ là một trong những giải pháp linh hoạt nhất nếu bạn sẵn sàng bao gồm một thư viện: https://github.com/s3u/JSONPath (nút và trình duyệt)

Đối với trường hợp sử dụng của bạn, đường dẫn json sẽ là:

$..items[1].name

vì thế:

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

1
Sử dụng eval () không phải là giải pháp tốt. Thay vào đó, chức năng hạng nhất có thể được sử dụng.
pradeep gowda

8

Chỉ trong trường hợp, bất kỳ ai truy cập câu hỏi này vào năm 2017 trở đi và tìm kiếm một cách dễ nhớ , đây là một bài đăng blog công phu về Truy cập các đối tượng lồng nhau trong JavaScript mà không bị xáo trộn bởi

Không thể đọc thuộc tính 'foo' của lỗi không xác định

1. Mẫu truy cập đối tượng lồng nhau của Oliver Steele

Cách dễ nhất và sạch nhất là sử dụng mẫu truy cập đối tượng lồng nhau của Oliver Steele

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

Với ký hiệu này, bạn sẽ không bao giờ gặp phải

Không thể đọc thuộc tính 'tên' của không xác định .

Về cơ bản, bạn kiểm tra xem người dùng có tồn tại không, nếu không, bạn sẽ tạo một đối tượng trống khi đang di chuyển. Bằng cách này, khóa cấp tiếp theo sẽ luôn được truy cập từ một đối tượng tồn tại hoặc một đối tượng trống , nhưng không bao giờ từ không xác định.

2. Truy cập các đối tượng lồng nhau bằng cách sử dụng Array Giảm

Để có thể truy cập các mảng lồng nhau, bạn có thể viết mảng giảm của riêng bạn.

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.

Ngoài ra còn có một loại tuyệt vời xử lý typy thư viện tối thiểu mà làm tất cả điều này cho bạn.


3
Câu hỏi này chủ yếu là về các thuộc tính truy cập tồn tại. Đã có một câu hỏi về những gì bạn đang đề cập (và đã bao gồm hầu hết các giải pháp của bạn): Truy cập các đối tượng lồng nhau Javascript một cách an toàn hoặc Truy cập các đối tượng JavaScript lồng nhau bằng khóa chuỗi . Nhưng dù sao đi nữa: "Thật không may, bạn không thể truy cập các mảng lồng nhau với thủ thuật này." Tại sao không? Mảng là đối tượng, vì vậy nó cũng hoạt động tốt. Bạn có thể cung cấp một ví dụ mà nó không?
Felix Kling

1
@FelixKling Khi chúng tôi cố gắng truy cập các mảng với mẫu Oliver Steele, chúng tôi sẽ không thể tạo mảng trên độ dài 'n' khi đang di chuyển và truy cập chỉ mục thứ n mà không gặp lỗi 'không xác định'. Ví dụ. ((user || {}).address || new Array(3))[1].name
Dinesh Pandiyan

3
Bạn không áp dụng mô hình của bạn một cách nhất quán. Tất nhiên ...[1].barsẽ dẫn đến một lỗi nếu phần tử 1không tồn tại. Nhưng đó cũng là trường hợp ....foo.barnếu fookhông tồn tại. Bạn cũng phải "bảo vệ" quyền truy cập 1, giống như bạn "bảo vệ" mọi quyền truy cập tài sản khác. Một mảng chỉ là một đối tượng. Một "phần tử mảng" chỉ là một thuộc tính. Áp dụng chính xác nó sẽ được (((user || {}).address || {})[1] || {}).name.
Felix Kling

1
Điều đó thật tuyệt. Nó không tấn công tôi theo cách này. Cảm ơn @FelixKling, tôi sẽ cập nhật các bài đăng trên blog.
Dinesh Pandiyan

2
@DineshPandiyan bạn nên tiết lộ rằng bạn là tác giả của typy, tôi chỉ đến đây sau khi đọc bài đăng trên blog của bạn
reggaeg Ức

8

Tôi thích JQuery hơn. Nó sạch hơn và dễ đọc.

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

7

Truy cập động đối tượng đa cấp.

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);

Fiddle làm việc: https://jsfiddle.net/andreitodorut/3mws3kjL/


6

Nếu bạn đang tìm kiếm một hoặc nhiều đối tượng đáp ứng các tiêu chí nhất định, bạn có một vài tùy chọn sử dụng truy vấn-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:""});

Ngoài ra còn có một singlesingleOrDefaulthọ làm việc rất giống firstfirstOrDefaulttương ứng. Sự khác biệt duy nhất là họ sẽ ném nếu tìm thấy nhiều hơn một trận đấu.

để giải thích thêm về truy vấn-js, bạn có thể bắt đầu với bài đăng này


Tôi rất muốn biết làm thế nào điều này có thể được cải thiện. bạn muốn để lại một bình luận?
Rune FS

6

The Underscore js Way

Đó là một thư viện JavaScript cung cấp toàn bộ các trình functional programmingtrợ giúp hữu ích mà không mở rộng bất kỳ đối tượng tích hợp nào.

Giải pháp:

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);
}

6

Câu hỏi cũ nhưng như không ai đề cập đến lodash (chỉ gạch dưới).

Trong trường hợp bạn đã sử dụng lodash trong dự án của mình, tôi nghĩ một cách thanh lịch để làm điều này trong một ví dụ phức tạp:

Lựa chọn 1

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

giống như:

Lựa chọn 2

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

Sự khác biệt giữa tùy chọn thứ nhất và thứ hai là trong Opt 1 nếu bạn thiếu một trong các thuộc tính (không xác định) trong đường dẫn bạn không gặp lỗi, nó sẽ trả về cho bạn tham số thứ ba.

Đối với bộ lọc mảng, lodash có _.find()nhưng tôi muốn sử dụng thường xuyên hơn filter(). Nhưng tôi vẫn nghĩ rằng phương pháp trên _.get()là siêu hữu ích khi làm việc với dữ liệu thực sự phức tạp. Tôi đã phải đối mặt với các API thực sự phức tạp trong quá khứ và nó rất tiện dụng!

Tôi hy vọng nó có thể hữu ích cho những ai đang tìm kiếm các tùy chọn để thao tác dữ liệu thực sự phức tạp mà tiêu đề ngụ ý.


5

Tôi không nghĩ người hỏi chỉ quan tâm đến một đối tượng lồng nhau ở cấp độ, vì vậy tôi trình bày bản demo sau đây để trình bày cách truy cập vào nút của đối tượng json lồng nhau sâu. Được rồi, hãy tìm nút có 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>


Làm thế nào để tôi truy cập đối tượng json lồng nhau bằng cách sử dụng các biến. dữ liệu = {a: {b: 'ss'}}; var key = ab data [key] không hoạt động
Pasupathi Rajamanickam 14/11/17

3

Bạn có thể sử dụng cú pháp jsonObject.keyđể truy cập giá trị. Và nếu bạn muốn truy cập một giá trị từ một mảng, thì bạn có thể sử dụng cú pháp jsonObjectArray[index].key.

Dưới đây là các ví dụ mã để truy cập các giá trị khác nhau để cung cấp cho bạn ý tưởng.

        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);


3

Cách tiếp cận năng động

Trong deep(data,key)hàm bên dưới , bạn có thể sử dụng keychuỗi tùy ý - trong trường hợp của bạn items[1].name(bạn có thể sử dụng ký hiệu mảng [i]ở bất kỳ mức nào) - nếu khóa không hợp lệ thì không xác định được trả về.


2

Một cách tiếp cận pythonic, đệ quy và chức năng để làm sáng tỏ các cây JSON tùy ý:

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)

trong đó dữ liệu là danh sách python (được phân tích cú pháp từ chuỗi văn bản 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']}
]

6
Câu hỏi này là về JavaScript, không phải Python. Không chắc chắn liệu có một câu hỏi tương đương cho Python.
Felix Kling

2

Hàm grep của jQuery cho phép bạn lọc qua một mảng:

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>


2
// 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;
}

2

Vào năm 2020, bạn có thể sử dụng @ babel / plugin-đề xuất-tùy chọn-chuỗi, rất dễ dàng để truy cập các giá trị lồng nhau trong một đối tượng.

 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-projection-optional-chained

https://github.com/tc39/proposed-optional-chained


-4

Của tôi stringdatađến từ tệp PHP nhưng vẫn còn, tôi chỉ ra ở đây trong var. Khi tôi trực tiếp đưa json của tôi vào objnó sẽ không có gì cho thấy đó là lý do tại sao tôi đặt tệp json của mình là

var obj=JSON.parse(stringdata); Vì vậy, sau đó tôi nhận được messageobj và hiển thị trong hộp cảnh báo, sau đó tôi nhận được datađó là mảng json và lưu trữ trong một biến ArrObjsau đó tôi đọc đối tượng đầu tiên của mảng đó với giá trị khóa như thế nàyArrObj[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);

2
Ví dụ gây nhầm lẫn vì stringjsonkhông phải là một chuỗi.
Felix Kling

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.