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

Aug 12 2012

Tôi có 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 để trích xuất thông tin, tức là truy cập một hoặc nhiều giá trị (hoặc khóa) cụ thể?

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 trong items?

Trả lời

1228 FelixKling Aug 12 2012 at 20:02

Sơ bộ

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

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

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

Mảng có dạng

[value, value, ...]

Cả mảng và đối tượng đều hiển thị 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òn đượ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 dấu chấm

const value = obj.someProperty;

hoặc ký hiệu dấu ngoặc , nếu tên thuộc tính không phải là tên định danh JavaScript hợp lệ [spec] hoặc tên là giá trị của một 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 ký hiệu dấ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];

Chờ đã ... còn JSON?

JSON là một biểu diễn dữ liệu dạng văn bản, giống như XML, YAML, CSV và những thứ khác. Để làm việc với những dữ liệu như vậy, trước tiên nó phải được chuyển đổi sang các kiểu dữ liệu JavaScript, tức là các 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). Cách phân tích cú pháp JSON được giải thích trong câu hỏi Phân tích cú pháp JSON trong JavaScript? .

Tài liệu đọc thêm

Cách truy cập các mảng và đối tượng là kiến ​​thức JavaScript cơ bản và do đó, bạn 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 tiếp ký hiệu 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 namemục thứ hai.

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

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 dấu chấm. Tài itemssả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 lại ký hiệu dấu chấm để truy cập 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 ta 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ự khiến 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 một tài sản nhưng tôi chỉ nhận được undefinedtrở lại?

Hầu hết thời gian khi bạn nhận được undefined, đối tượng / mảng chỉ đơ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ố gắng 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ì sẽ xảy ra nếu tên thuộc tính là động và tôi không biết trước chúng?

Nếu tên thuộc tính không xác định hoặc chúng ta muốn truy cập tất cả các thuộc tính của một đối tượng / phần tử 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 mảng để lặp qua tất cả các thuộc tính / phần tử.

Các đối tượng

Để lặp lại trên tất cả các thuộc tính của data, chúng ta có thể lặp qua đối tượng như sau:

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 đối tượng đến từ đâu (và bạn muốn làm gì), bạn có thể phải kiểm tra trong mỗi lần lặp xem thuộc tính có thực sự là thuộc tính của đối tượng hay là thuộc tính được kế thừa. Bạn có thể thực hiện việc này với Object#hasOwnProperty [MDN] .

Thay vì for...invới hasOwnProperty, bạn có thể sử dụng Object.keys [MDN] để lấy một mảng 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 qua 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 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à hoạt động không tốt 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 sự 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 môi trường hỗ trợ ES2015 (ES6), bạn cũng có thể sử dụng vòng lặp [MDN] , vòng lặp này không chỉ hoạt động cho các mảng mà còn cho bất kỳ vòng lặp nào có thể lặp lại :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 có thể lặp, không có "chỉ mục" để truy cập hoặc sử dụng.


Điều gì sẽ 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 (tức là có bao nhiêu đối tượng lồng nhau) mà nó có, cũng có thể không xác định. Cách 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ụ như 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] vào từng cấp của cấu trúc dữ liệu.

Dưới đây là một ví dụ để lấy 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);

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

Một cách chung 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ụ thêm 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 giá trị đó (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;
}

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



Người trợ giúp

Vì 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ử đều là đố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 rằng đó 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. Tuy nhiên, 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.

80 vitmalina May 14 2013 at 10:29

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 bằng nhau.

36 holographic-principle Jun 29 2013 at 16:15

Trong trường hợp bạn đang cố gắng truy cập một 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 điều đó 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"}

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

Chỉ 2 xu của tôi.

34 MichałPerłakowski Oct 23 2016 at 01:38

Đố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 ràng buộc thisgiá trị về mặt từ vựng.

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

Object.keys()trả về mảng khóa của đối tượng, Object.values()trả về mảng giá trị của đối tượng và Object.entries()trả về mảng khóa của đối tượng và các giá trị tương ứng trong một đị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 vòng lặp for-of và phân công cơ cấu lại

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 kết quả của Object.entries()một phi của vòng lặpdestructuring phân công .

Vòng lặp for cho phép bạn lặp lại các phần tử của 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 nên sử dụng constnếu chúng ta không có ý định sửa đổi element).

Phép gán hủy 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 đó cho 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, cấu trúc 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ể không có 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ư sau:

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

26 TravisJ Aug 19 2014 at 02:20

Đô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. Ví dụ, cách tiếp cận đơn giản là cấp độ đầu tiên

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

Nhưng điều này thường không đúng 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 thức đệ quy được tận dụng sẽ phụ thuộc vào loại dữ liệu được tìm kiếm. Nếu có các câu lệnh đ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 được truy cập đã được biết trước, nhưng đường dẫn phức tạp, ví dụ như 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 rằng bạn muốn nhận được 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 một cách đệ 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 Democách tiếp cận này đang được sử dụng.

14 AlexKeySmith May 06 2016 at 17:45

Câu hỏi này khá cũ, vì vậy nó là một bản cập nhật đương đại. Với sự ra mắt của ES2015, có nhiều lựa chọn thay thế để lưu giữ dữ liệu bạn yêu cầu. Bây giờ có một tính năng được gọi là cấu trúc đố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 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ì truy cập mảng đơn giản dễ đọc hơn, nhưng nó có ích khi chia nhỏ các đối tượng nói chung.

Đây là phần giới thiệu rất ngắn gọn về trường hợp sử dụng cụ thể của bạn, cấu trúc 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 Chuyển nhượng cấu trúc của Mozilla để tìm hiểu thêm.

14 Evgeny Feb 15 2018 at 17:06

Để 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 trong đố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 chính xác tên 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ìm kiếm động thông qua cấu trúc dữ liệu là bắt buộc. Một số gợi ý ở đây rằng việc 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 con đường 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 hãy lấy đối tượng có khóa items, đối tượng này xảy ra là một mảng. Sau đó lấy 1phần tử -st (0 mảng chỉ số). Cuối cùng lấy đối tượng có khóa nametrong phần tử mảng đó, đối tượng này sẽ xảy ra 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ả điều này trở nên dễ dàng hơn -

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

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

14 Johnny Aug 20 2018 at 06:01
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 phần tử 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-algorithm-and-data-structures/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-algorithm-and-data-structures/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#Bracket_notation

Truy cập tài sản thông qua dot walk: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_Accessors#Dot_notation

13 Sergey Jul 03 2017 at 02:08

Bạn có thể sử dụng lodash _gethàm:

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

_.get(object, 'a[0].b.c');
// => 3
10 DineshPandiyan Jul 07 2018 at 15:32

Đề phòng trường hợp có bất kỳ ai truy cập câu hỏi này vào năm 2017 hoặc mới hơn và đang tìm kiếm một cách dễ nhớ , đây là một bài đăng trên blog phức tạp về Truy cập các đối tượng lồng nhau trong JavaScript mà không bị che khuất 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 hay không, nếu không, bạn 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 Reduce

Để có thể truy cập vào các mảng lồng nhau, bạn có thể viết giảm sử dụng mảng của riêng mình.

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ý thư viện tối thiểu typy mà làm tất cả điều này cho bạn.

9 Andrejs Jun 26 2014 at 19:43

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 đưa vào 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");
9 AndreiTodorut Jan 25 2018 at 17:24

Truy cập động đối tượng nhiều 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);

Làm việc fiddle: https://jsfiddle.net/andreitodorut/3mws3kjL/

8 RudyHinojosa Feb 24 2016 at 22:55

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

$.each($.parseJSON(data), function (key, value) {
  alert(value.<propertyname>);
});
6 RuneFS Jun 17 2015 at 19:16

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 số tùy chọn bằng cách sử dụng 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:""});

Ngoài ra còn có a singlevà a singleOrDefaultchúng hoạt động tương tự firstfirstOrDefaulttương ứng. Sự khác biệt duy nhất là họ sẽ ném nếu nhiều hơn một trận đấu được tìm thấy.

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

6 MohanDere Aug 13 2016 at 17:39

Cách gạch dưới js

Đây là một thư viện JavaScript cung cấp một mớ hỗn độn các trình functional programmingtrợ giúp hữu ích mà không cần 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 ThiagoC.SVentura Jul 01 2017 at 18:46

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 đang sử dụng lodash trong dự án của mình, tôi nghĩ một cách đơn giản để làm điều này trong một ví dụ phức tạp:

Chọn 1

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

giống như:

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 Lựa chọn 1 nếu bạn có một trong các thuộc tính bị thiếu (không xác định) trong đường dẫn mà 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 thường 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. Trước đây tôi đã phải đối mặt với các API thực sự phức tạp 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úng dữ liệu thực sự phức tạp như tiêu đề ngụ ý.

5 dabeng Feb 22 2017 at 16:00

Tôi không nghĩ rằng người hỏi chỉ quan tâm đến một đối tượng lồng nhau ở mức độ, vì vậy tôi trình bày bản trình diễn sau để chứng minh 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>

4 Rathore Jan 08 2020 at 13:51

Vào năm 2020, bạn có thể sử dụng @ babel / plugin-suggest-option-chaining, 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-proposal-optional-chaining

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

4 RahulVala Jan 17 2020 at 23:19

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

4 KamilKiełczewski Jun 26 2019 at 12:01

Phương pháp tiếp cận động

Trong deep(data,key)hàm dưới đây , 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ỳ cấp nào) - nếu khóa không hợp lệ thì trả về không xác định.

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

4 timnavigate Jun 18 2020 at 16:50

Đó là lời giải thích đơn giản:

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

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

/*
2. `item` 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);

2 Noname Aug 28 2017 at 18:25

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 MichaelDimmitt Dec 04 2019 at 05:50
// 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;
}
1 pX0r Dec 29 2016 at 02:53

Phương pháp tiếp cận pythonic, đệ quy và hàm để 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']}
]
vincent Oct 24 2020 at 22:04

Lưu ý: Câu trả lời này giả định rằng chúng tôi đang tìm kiếm mục id = 2


Cân nhắc sử dụng quét đối tượng nếu bạn có nhu cầu xử lý dữ liệu phức tạp hơn. Nó rất mạnh khi bạn quấn quanh đầu. Đối với ví dụ của bạn, bạn có thể sử dụng như sau:

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

const find = (id, data) => objectScan(['items[*].id'], {
  abort: true,
  rtn: 'parent',
  filterFn: ({ value }) => value === id
})(data);

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

console.log(find(2, data));
// => { id: 2, name: 'bar' }