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?

923
Felix Kling 2012-08-13 03:02.

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?

25 answers

1228
Felix Kling 2012-08-13 03: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 2013-05-14 17: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 2013-06-29 23: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 2016-10-23 08: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
Travis J 2014-08-19 09: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
Alex KeySmith 2016-05-07 00: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 2018-02-16 00: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 2018-08-20 13: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 2017-07-03 09: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
Dinesh Pandiyan 2018-07-07 22: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 2014-06-27 02: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
Andrei Todorut 2018-01-26 00: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
Rudy Hinojosa 2016-02-25 05: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
Rune FS 2015-06-18 02: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
Mohan Dere 2016-08-14 00: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
Thiago C. S Ventura 2017-07-02 01: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 2017-02-22 23: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 2020-01-08 20: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
Rahul Vala 2020-01-18 06: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
Kamil Kiełczewski 2019-06-26 19: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 2020-06-18 23: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 2017-08-29 01: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
Michael Dimmitt 2019-12-04 12: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 2016-12-29 09: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']}
]
0
vincent 2020-10-25 05: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' }

Related questions

MORE COOL STUFF

Cate Blanchett chia tay chồng sau 3 ngày bên nhau và vẫn kết hôn với anh ấy 25 năm sau

Cate Blanchett chia tay chồng sau 3 ngày bên nhau và vẫn kết hôn với anh ấy 25 năm sau

Cate Blanchett đã bất chấp những lời khuyên hẹn hò điển hình khi cô gặp chồng mình.

Tại sao Michael Sheen là một diễn viên phi lợi nhuận

Tại sao Michael Sheen là một diễn viên phi lợi nhuận

Michael Sheen là một diễn viên phi lợi nhuận nhưng chính xác thì điều đó có nghĩa là gì?

Hallmark Star Colin Egglesfield Các món ăn gây xúc động mạnh đối với người hâm mộ tại RomaDrama Live! [Loại trừ]

Hallmark Star Colin Egglesfield Các món ăn gây xúc động mạnh đối với người hâm mộ tại RomaDrama Live! [Loại trừ]

Ngôi sao của Hallmark Colin Egglesfield chia sẻ về những cuộc gặp gỡ với người hâm mộ ly kỳ tại RomaDrama Live! cộng với chương trình INSPIRE của anh ấy tại đại hội.

Tại sao bạn không thể phát trực tuyến 'chương trình truyền hình phía Bắc'

Tại sao bạn không thể phát trực tuyến 'chương trình truyền hình phía Bắc'

Bạn sẽ phải phủi sạch đầu đĩa Blu-ray hoặc DVD để xem tại sao Northern Exposure trở thành một trong những chương trình nổi tiếng nhất của thập niên 90.

Where in the World Are You? Take our GeoGuesser Quiz

Where in the World Are You? Take our GeoGuesser Quiz

The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!

8 công dụng tuyệt vời của Baking Soda và Giấm

8 công dụng tuyệt vời của Baking Soda và Giấm

Bạn biết đấy, hai sản phẩm này là nguồn điện để làm sạch, riêng chúng. Nhưng cùng với nhau, chúng có một loạt công dụng hoàn toàn khác.

Hạn hán, biến đổi khí hậu đe dọa tương lai của thủy điện Hoa Kỳ

Hạn hán, biến đổi khí hậu đe dọa tương lai của thủy điện Hoa Kỳ

Thủy điện rất cần thiết cho lưới điện của Hoa Kỳ, nhưng nó chỉ tạo ra năng lượng khi có nước di chuyển. Bao nhiêu nhà máy thủy điện có thể gặp nguy hiểm khi các hồ và sông cạn kiệt?

Quyên góp tóc của bạn để giúp giữ nước sạch của chúng tôi

Quyên góp tóc của bạn để giúp giữ nước sạch của chúng tôi

Tóc tỉa từ các tiệm và các khoản quyên góp cá nhân có thể được tái sử dụng như những tấm thảm thấm dầu và giúp bảo vệ môi trường.

Xem đoạn giới thiệu cho bộ phim chuyển thể đầy khói lửa, có sự góp mặt của ngôi sao Edward Norton từ phim Motherless Brooklyn của Jonathan Lethem

Xem đoạn giới thiệu cho bộ phim chuyển thể đầy khói lửa, có sự góp mặt của ngôi sao Edward Norton từ phim Motherless Brooklyn của Jonathan Lethem

Edward Norton đã muốn đưa cuốn tiểu thuyết Motherless Brooklyn của Jonathan Lethem's Joycean 1999 lên màn ảnh kể từ khi nó được xuất bản. Bây giờ, 20 năm sau, một đoạn giới thiệu đã xuất hiện cho câu chuyện sôi nổi, đưa câu chuyện của Lethem trở lại những năm 1950 với rất nhiều gương mặt quen thuộc.

Cách dễ dàng chọn không tham gia trọng tài ràng buộc thẻ Apple

Cách dễ dàng chọn không tham gia trọng tài ràng buộc thẻ Apple

Có thích thú khi sử dụng Thẻ Apple mới của bạn không? Trước khi bạn bắt đầu chi tiêu, có một nhiệm vụ bổ sung cần xem xét: chọn không tham gia trọng tài ràng buộc. Bạn sẽ phát hiện ra các điều khoản trọng tài ràng buộc trong nhiều thỏa thuận tài chính vì nó giúp ngăn các ngân hàng và đối tác kinh doanh của họ không phải ra tòa.

Những người chơi Fortnite World Cup không ghi bàn có cảm giác hài hước về điều đó

Những người chơi Fortnite World Cup không ghi bàn có cảm giác hài hước về điều đó

Điểm số tại vòng chung kết Fortnite World Cup Solo hôm nay là rất lớn, với người chiến thắng Bugha ghi được nhiều hơn 26 điểm so với người về thứ hai là Psalm. Nhưng không phải ai cũng có thể giành chiến thắng: Bốn cầu thủ ra về với 0 điểm, nhưng — ít nhất là trên Twitter — họ là những người thể thao tốt về điều đó.

Báo cáo: Cánh cửa tuyển sinh có thể đã mở cho các ứng viên UCLA có mối quan hệ có ảnh hưởng

Báo cáo: Cánh cửa tuyển sinh có thể đã mở cho các ứng viên UCLA có mối quan hệ có ảnh hưởng

Huấn luyện viên trưởng của bộ môn thể dục dụng cụ UCLA Valorie Kondos-Field theo dõi Katelyn Ohashi thi đấu thăng bằng trong trận gặp Stanford tại Pauley Pavilion vào ngày 10 tháng 3 năm 2019 ở Los Angeles, California. Vụ bê bối gian lận tuyển sinh đại học tiết lộ các chi tiết của một quá trình chính thức hóa để đưa những đứa trẻ thất bại của các gia đình giàu có và nổi tiếng vào các trường đại học đáng tin cậy và danh tiếng, sử dụng một "cửa phụ" đắt tiền cho các bậc cha mẹ mà sự giàu có của họ khiến họ không có cơ hội. chỉ cần tài trợ cho một cánh mới trong khuôn viên trường.

Nicky Hilton Forced to Borrow Paris' 'I Love Paris' Sweatshirt After 'Airline Loses All [My] Luggage'

Nicky Hilton Forced to Borrow Paris' 'I Love Paris' Sweatshirt After 'Airline Loses All [My] Luggage'

Nicky Hilton Rothschild's luggage got lost, but luckily she has an incredible closet to shop: Sister Paris Hilton's!

Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa

Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa

Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa. Từ Hollywood đến New York và mọi nơi ở giữa, hãy xem các ngôi sao yêu thích của bạn đang làm gì!

17 tuổi bị đâm chết trong khi 4 người khác bị thương trong một cuộc tấn công bằng dao trên sông Wisconsin

17 tuổi bị đâm chết trong khi 4 người khác bị thương trong một cuộc tấn công bằng dao trên sông Wisconsin

Các nhà điều tra đang xem xét liệu nhóm và nghi phạm có biết nhau trước vụ tấn công hay không

Thanh thiếu niên, Gia đình Florida Hội đồng quản trị trường học về Luật 'Không nói đồng tính': 'Buộc chúng tôi tự kiểm duyệt'

Thanh thiếu niên, Gia đình Florida Hội đồng quản trị trường học về Luật 'Không nói đồng tính': 'Buộc chúng tôi tự kiểm duyệt'

Vụ kiện, nêu tên một số học khu, lập luận rằng dự luật "Không nói đồng tính" được ban hành gần đây của Florida "có hiệu quả im lặng và xóa bỏ học sinh và gia đình LGBTQ +"

Hãy tưởng tượng tạo ra một chiến lược nội dung thực sự CHUYỂN ĐỔI. Nó có thể.

Hãy tưởng tượng tạo ra một chiến lược nội dung thực sự CHUYỂN ĐỔI. Nó có thể.

Vào năm 2021, tôi khuyến khích bạn suy nghĩ lại mọi thứ bạn biết về khách hàng mà bạn phục vụ và những câu chuyện bạn kể cho họ. Lùi lại.

Sự mất mát của voi ma mút đã mở ra trái tim tôi để yêu

Sự mất mát của voi ma mút đã mở ra trái tim tôi để yêu

Vào ngày sinh nhật thứ 9 của Felix The Cat, tôi nhớ về một trong những mất mát lớn nhất trong cuộc đời trưởng thành của tôi - Sophie của tôi vào năm 2013. Tôi đã viết bài luận này và chia sẻ nó trên nền tảng này một thời gian ngắn vào năm 2013.

Khi bạn không thể trở thành người mà Internet muốn bạn trở thành

Khi bạn không thể trở thành người mà Internet muốn bạn trở thành

Tôi ghét từ "tàu đắm". Mọi người cảm thấy thoải mái trong la bàn đạo đức của riêng mình, và khi làm như vậy, họ thấy mình vượt qua sự phán xét.

Tầm nhìn đám mây phi tập trung của DFINITY Blockchain

Lưu ý của người biên tập: Bạn đang xem tài liệu lỗi thời từ blog DFINITY đang được bảo quản cho mục đích lưu trữ.

Tầm nhìn đám mây phi tập trung của DFINITY Blockchain

Bài đăng này khám phá tầm nhìn về đám mây phi tập trung của nhóm DFINITY và cách nó liên quan đến các nhà cung cấp blockchain truyền thống và đám mây hiện có như Amazon Web Services. Các minh chứng về công nghệ DFINITY được áp dụng bởi một mạng lưới quy mô lớn sẽ được thực hiện vào mùa thu năm 2017, sau đó sẽ được gây quỹ Chính cho quỹ hỗ trợ phi lợi nhuận, với mạng “đám mây mở” dự kiến ​​sẽ ra mắt vào đầu mùa hè năm 2018 .

Language