Làm cách nào để lặp qua hoặc liệt kê một đối tượng JavaScript?


2880

Tôi có một đối tượng JavaScript như sau:

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

Bây giờ tôi muốn lặp qua tất cả pcác yếu tố ( p1, p2, p3...) Và lấy key và giá trị của họ. Làm thế nào tôi có thể làm điều đó?

Tôi có thể sửa đổi đối tượng JavaScript nếu cần thiết. Mục tiêu cuối cùng của tôi là lặp qua một số cặp giá trị chính và nếu có thể tôi muốn tránh sử dụng eval.


9
Tôi đã thay đổi JSON thành JavaScript (đối tượng) để tránh nhầm lẫn giữa nghĩa đen và JSON của đối tượng.
Felix Kling

Câu trả lời:


4367

Bạn có thể sử dụng các for-invòng lặp như được hiển thị bởi những người khác. Tuy nhiên, bạn cũng phải đảm bảo rằng khóa bạn nhận được là một thuộc tính thực tế của một đối tượng và không đến từ nguyên mẫu.

Đây là đoạn trích:

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

for (var key in p) {
    if (p.hasOwnProperty(key)) {
        console.log(key + " -> " + p[key]);
    }
}

Thay thế cho đối tượng với Object.keys ():

var p = {
    0: "value1",
    "b": "value2",
    key: "value3"
};

for (var key of Object.keys(p)) {
    console.log(key + " -> " + p[key])
}

Lưu ý việc sử dụng for-ofthay vì for-in, nếu không được sử dụng, nó sẽ trả về không xác định trên các thuộc tính được đặt tên và Object.keys()đảm bảo chỉ sử dụng các thuộc tính riêng của đối tượng mà không có toàn bộ thuộc tính chuỗi nguyên mẫu

Sử dụng Object.entries()phương pháp mới :

Lưu ý: Phương pháp này không được Internet Explorer hỗ trợ. Bạn có thể cân nhắc sử dụng Polyfill cho các trình duyệt cũ hơn.

const p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

for (let [key, value] of Object.entries(p)) {
  console.log(`${key}: ${value}`);
}

34
Sẽ đề nghị bạn thay đổi dòng cảnh báo chỉ để rõ ràng thànhalert(key + " -> " + JSON.stringify(p[key]));
Steve Midgley

80
Bạn có thể giải thích sự cần thiết của hasOwnProperty? Ý của bạn là gì bởi nguyên mẫu?
kamaci

331
Trong javascript, mọi đối tượng đều có một cặp các cặp khóa-giá trị tích hợp có thông tin meta. Khi bạn lặp qua tất cả các cặp khóa-giá trị cho một đối tượng bạn cũng sẽ lặp qua chúng. hasOwnPropery () lọc những cái này ra.
danieltalsky

57
Thật ra, vì ... không bị phản đối. Đối với mỗi ... trong là. Nhưng tôi thực sự thích thuật ngữ khảo cổ học ... Tôi sẽ phải bắt đầu sử dụng nó.
Ben Y

17
mỗi đối tượng trong javascript (thực sự là một cặp khóa-giá trị) có một thuộc tính được gọi là __proto__hoặc prototype. Thuộc tính này có một tham chiếu đến đối tượng cha của nó. Một đối tượng tự động thừa kế tài sản từ cha mẹ của nó. Đây là lý do của việc sử dụng hasOwnProperty, điều này biểu thị rằng chúng ta quan tâm đến tài sản của đối tượng chứ không phải tài sản mẹ của nó.
Zubair Alam

1104

Trong ECMAScript 5, bạn có thể kết hợp Object.keys()Array.prototype.forEach():

var obj = { first: "John", last: "Doe" };

Object.keys(obj).forEach(function(key) {
    console.log(key, obj[key]);
});

ECMAScript 6 cho biết thêm for...of:

for (const key of Object.keys(obj)) {
    console.log(key, obj[key]);
}

ECMAScript 8 cho biết thêm Object.entries()việc tránh phải tìm kiếm từng giá trị trong đối tượng ban đầu:

Object.entries(obj).forEach(
    ([key, value]) => console.log(key, value)
);

Bạn có thể kết hợp for...of, phá hủy và Object.entries:

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

Cả hai Object.keys()Object.entries()lặp lại các thuộc tính theo cùng một thứ tự như một for...invòng lặp nhưng bỏ qua chuỗi nguyên mẫu . Chỉ các thuộc tính vô số của riêng đối tượng được lặp lại.


21
Tại sao tiêu chuẩn Object.forEach(obj, function (value, key) {...})không cung cấp ? :( Chắc chắn obj.forEach(function...)sẽ ngắn hơn và bổ sung Array.prototype.forEach, nhưng điều đó sẽ có nguy cơ khiến các đối tượng xác định forEachtài sản riêng của họ . Tôi cho rằng những người Object.keysbảo vệ chống lại cuộc gọi lại sửa đổi các khóa của đối tượng.
David Harkness

7
Object.forEach = function (obj, callback) { Object.keys(obj).forEach(function (key) { callback(obj[key], key); }); }
David Harkness

7
@DavidHarkness Có Object.entries trong ES2017. Ở đó bạn có thể thực hiện các thao tác sau: Object.entries(obj).map/forEach(([key, value]) => console.log(key, value))([key, value] là phá hủy mảng, để truy cập trực tiếp cả hai mục. Và bạn phải bọc các tham số trong các parens bổ sung.)
Andreas Linnert

Làm thế nào để tôi nhận được indexchìa khóa trong json? Hoặc nếu cần tôi nên sử dụng một bộ đếm riêng?
Saravanabalagi Ramachandran

3
for...oflà tiêu chuẩn ES6, không phải ES2016.
Rax Weber

342

Bạn phải sử dụng vòng lặp for-in

Nhưng hãy cẩn thận khi sử dụng loại vòng lặp này, bởi vì điều này sẽ lặp tất cả các thuộc tính dọc theo chuỗi nguyên mẫu .

Do đó, khi sử dụng các vòng lặp for, hãy luôn sử dụng hasOwnPropertyphương thức để xác định xem thuộc tính hiện tại trong lần lặp có thực sự là một thuộc tính của đối tượng bạn đang kiểm tra hay không:

for (var prop in p) {
    if (!p.hasOwnProperty(prop)) {
        //The current property is not a direct property of p
        continue;
    }
    //Do your logic with the property here
}

31
Điều này tốt hơn giải pháp của levik vì nó cho phép logic chính chỉ là một vòng lặp lồng nhau thay vì hai vòng; làm cho việc đọc mã dễ dàng hơn. Mặc dù tôi đã mất các dấu ngoặc quanh tiếp tục; chúng là thừa.
SystemicPlural

52
Tôi sẽ không loại bỏ { }cá nhân bởi vì ifkhông có họ làm cho nó không rõ ràng một phần của ifcái gì và cái gì không. Nhưng tôi đoán đó chỉ là vấn đề quan điểm :)
pimvdb

34
Có, tôi thích giữ { }chủ yếu để tránh nhầm lẫn nếu sau này cần thêm một cái gì đó vào ifphạm vi.
Andreas Grech

8
Đọc bình luận trước đây của tôi, tôi nhận ra rằng tôi đã không sử dụng các thuật ngữ chính xác, bởi vì tôi đã nói "nếu phạm vi"; nhưng hãy nhớ rằng JavaScript chỉ có phạm vi chức năng. Vì vậy, những gì tôi thực sự có nghĩa là "nếu khối".
Andreas Grech

1
eomeroff, nếu bạn thực sự lo lắng về điều đó, bạn luôn có thể làm điều gì đó như: Object.prototype.hasOwnProperty.call(p, prop) Tuy nhiên, điều này cũng không thể bảo vệ chống lại các thao tác đối với Object.prototype ...
jordancpaul

252

Câu hỏi sẽ không hoàn thành nếu chúng ta không đề cập đến các phương pháp thay thế để lặp qua các đối tượng.

Ngày nay, nhiều thư viện JavaScript nổi tiếng cung cấp các phương thức riêng để lặp lại các bộ sưu tập, tức là trên các mảng , các đối tượngcác đối tượng giống như mảng . Các phương pháp này thuận tiện để sử dụng và hoàn toàn tương thích với bất kỳ trình duyệt nào.

  1. Nếu bạn làm việc với jQuery , bạn có thể sử dụng jQuery.each()phương thức. Nó có thể được sử dụng để lặp lại liên tục trên cả hai đối tượng và mảng:

    $.each(obj, function(key, value) {
        console.log(key, value);
    });
  2. Trong Underscore.js, bạn có thể tìm thấy phương thức _.each(), lặp lại danh sách các phần tử, mang lại lần lượt từng hàm cho một hàm được cung cấp (chú ý đến thứ tự các đối số trong hàm iteratee !):

    _.each(obj, function(value, key) {
        console.log(key, value);
    });
  3. Lo-Dash cung cấp một số phương thức để lặp lại các thuộc tính đối tượng. Basic _.forEach()(hoặc bí danh _.each()) rất hữu ích cho việc lặp qua cả hai đối tượng và mảng, tuy nhiên (!) Các đối tượng có thuộc lengthtính được xử lý như mảng và để tránh hành vi này nên sử dụng _.forIn()_.forOwn()các phương thức (chúng cũng có valueđối số đến trước):

    _.forIn(obj, function(value, key) {
        console.log(key, value);
    });

    _.forIn()Lặp lại các thuộc tính vô số của riêng và được kế thừa của một đối tượng, trong khi _.forOwn()chỉ lặp lại trên các thuộc tính riêng của một đối tượng (về cơ bản kiểm tra đối với hasOwnPropertychức năng). Đối với các đối tượng đơn giản và đối tượng bằng chữ, bất kỳ phương thức nào trong số này sẽ hoạt động tốt.

Nói chung tất cả các phương thức được mô tả có cùng hành vi với bất kỳ đối tượng được cung cấp. Bên cạnh việc sử dụng for..invòng lặp gốc thường sẽ nhanh hơn bất kỳ sự trừu tượng hóa nào, chẳng hạn như jQuery.each(), các phương thức này dễ sử dụng hơn đáng kể, yêu cầu ít mã hóa hơn và cung cấp xử lý lỗi tốt hơn.


4
Để lấy giá trị: $ .each (obj, function (key, value) {console.log (value.title);});
Ravi Ram

2
Thật buồn cười là cách gạch dưới và jquery thay đổi các tham số :)
ppasler

52

Trong ECMAScript 5, bạn có cách tiếp cận mới trong các trường lặp theo nghĩa đen - Object.keys

Thêm thông tin bạn có thể thấy trên MDN

Lựa chọn của tôi dưới đây là giải pháp nhanh hơn trong các phiên bản trình duyệt hiện tại (Chrome30, IE10, FF25)

var keys = Object.keys(p),
    len = keys.length,
    i = 0,
    prop,
    value;
while (i < len) {
    prop = keys[i];
    value = p[prop];
    i += 1;
}

Bạn có thể so sánh hiệu suất của phương pháp này với các triển khai khác nhau trên jsperf.com :

Hỗ trợ trình duyệt bạn có thể thấy trên bảng compat của Kangax

Đối với trình duyệt cũ, bạn có polyfill đơn giảnđầy đủ

CẬP NHẬT:

so sánh hiệu suất cho tất cả các trường hợp phổ biến nhất trong câu hỏi này về perfjs.info:

lặp lại đối tượng


Thật vậy, tôi chỉ muốn đăng phương pháp này. Nhưng bạn đã đánh bại tôi vì điều đó :(
Jamie Hutber 20/03/2016

50

Lời nói đầu:

  • Các thuộc tính đối tượng có thể là của riêng (thuộc tính nằm trên chính đối tượng) hoặc được kế thừa (không phải trên chính đối tượng, trên một trong các nguyên mẫu của nó).
  • Thuộc tính đối tượng có thể đếm được hay không đếm được . Các thuộc tính không liệt kê được bỏ qua rất nhiều bảng liệt kê / mảng tài sản.
  • Tên thuộc tính có thể là chuỗi hoặc Biểu tượng. Các thuộc tính có tên là Biểu tượng được bỏ qua rất nhiều bảng liệt kê / mảng thuộc tính.

Ở đây vào năm 2018, các tùy chọn của bạn để lặp qua các thuộc tính của một đối tượng là (một số ví dụ tuân theo danh sách):

  1. for-in[ MDN , spec ] - Một cấu trúc vòng lặp lặp qua tên của các thuộc tính có thể đếm được của một đối tượng , bao gồm cả các thuộc tính được kế thừa, có tên là các chuỗi
  2. Object.keys[ MDN , spec ] - Một hàm cung cấp một mảng các tên của các thuộc tính riêng , có thể đếm được có tên là các chuỗi.
  3. Object.values[ MDN , spec ] - Một hàm cung cấp một mảng các giá trị thuộc tính riêng , có thể đếm được của một đối tượng .
  4. Object.entries[ MDN , spec ] - Một hàm cung cấp một mảng các tên giá trị của các thuộc tính riêng , có thể đếm được của mỗi đối tượng (mỗi mục trong mảng là một [name, value]mảng).
  5. Object.getOwnPropertyNames[ MDN , spec ] - Một hàm cung cấp một mảng các tên của các thuộc tính riêng của đối tượng (ngay cả các thuộc tính không đếm được) có tên là các chuỗi.
  6. Object.getOwnPropertySymbols[ MDN , spec ] - Một hàm cung cấp một mảng các tên của các thuộc tính riêng của đối tượng (ngay cả các thuộc tính không thể đếm được) có tên là Biểu tượng.
  7. Reflect.ownKeys[ MDN , spec ] - Một hàm cung cấp một mảng các tên của các thuộc tính riêng của đối tượng (ngay cả các thuộc tính không thể đếm được), cho dù các tên đó là chuỗi hay Biểu tượng.
  8. Nếu bạn muốn tất cả các thuộc tính của một đối tượng, bao gồm cả những người thừa hưởng không đếm được, bạn cần phải sử dụng một vòng lặp và Object.getPrototypeOf[ MDN , đặc tả ] và sử dụng Object.getOwnPropertyNames, Object.getOwnPropertySymbolshoặc Reflect.ownKeystrên từng đối tượng trong chuỗi ban đầu (ví dụ ở dưới cùng của câu trả lời này).

Với tất cả trong số họ ngoại trừ for-in, bạn muốn sử dụng một số loại vòng lặp xây dựng trên mảng ( for, for-of, forEach, vv).

Ví dụ:

for-in:

Object.keys (với một for-ofvòng lặp, nhưng bạn có thể sử dụng bất kỳ cấu trúc lặp nào) :

Object.values:

Object.entries:

Object.getOwnPropertyNames:

Object.getOwnPropertySymbols:

Reflect.ownKeys:

Tất cả các thuộc tính , bao gồm cả những tài sản không được liệt kê:


Đẹp bổ sung các thuộc tính đối tượng vô số / không enumberable.
serraosays

49

Bạn chỉ có thể lặp đi lặp lại trên nó như:

for (var key in p) {
  alert(p[key]);
}

Lưu ý rằng keysẽ không lấy giá trị của tài sản, nó chỉ là một giá trị chỉ mục.


13
Điều này được lặp đi lặp lại và thậm chí không hoàn toàn chính xác. Bạn cần kiểm tra hasOwnProperty để thực hiện công việc này đúng cách
Vatsal

4
Ban đầu tôi đã đánh giá thấp điều này dựa trên nhận xét trên cho đến khi tôi nhận ra rằng câu trả lời này xuất hiện trước, do đó không được "lặp lại". Nó có thể không đầy đủ nhưng chỉ hoạt động tốt trong nhiều trường hợp.
billynoah

27

Vì es2015 đang ngày càng phổ biến hơn nên tôi đăng câu trả lời này bao gồm việc sử dụng trình tạo và trình lặp để lặp lại một cách trơn tru [key, value] các cặp. Như có thể trong các ngôn ngữ khác, ví dụ như Ruby.

Ok đây là một mã:

const MyObject = {
  'a': 'Hello',
  'b': 'it\'s',
  'c': 'me',
  'd': 'you',
  'e': 'looking',
  'f': 'for',
  [Symbol.iterator]: function* () {
    for (const i of Object.keys(this)) {
      yield [i, this[i]];
    }
  }
};

for (const [k, v] of MyObject) {
  console.log(`Here is key ${k} and here is value ${v}`);
}

Tất cả thông tin về cách bạn có thể thực hiện một trình lặp và trình tạo mà bạn có thể tìm thấy tại trang Mozilla của nhà phát triển.

Hy vọng nó đã giúp được ai đó.

BIÊN TẬP:

ES2017 sẽ bao gồm Object.entriesviệc sẽ lặp lại [key, value]các cặp trong các đối tượng dễ dàng hơn. Bây giờ được biết rằng nó sẽ là một phần của tiêu chuẩn theo ts39 thông tin giai đoạn .

Tôi nghĩ rằng đã đến lúc cập nhật câu trả lời của mình để cho nó trở nên tươi hơn so với bây giờ.

const MyObject = {
  'a': 'Hello',
  'b': 'it\'s',
  'c': 'me',
  'd': 'you',
  'e': 'looking',
  'f': 'for',
};

for (const [k, v] of Object.entries(MyObject)) {
  console.log(`Here is key ${k} and here is value ${v}`);
}

Bạn có thể tìm hiểu thêm về cách sử dụng trên trang MDN


Điều này có vẻ hoàn toàn thừa / không cần thiết với tôi. Bạn sẽ thêm nó vào mọi đối tượng trong hệ thống của bạn? Tôi nghĩ rằng việc cung cấp một trình vòng lặp là để bạn có thể thực hiện `for (const [k, v] của myObject) '. Nó chỉ giống như mã bổ sung cung cấp ít giá trị bổ sung.
Dean Radcliffe

22
for(key in p) {
  alert( p[key] );
}

Lưu ý: bạn có thể thực hiện việc này qua các mảng, nhưng bạn cũng sẽ lặp lại lengthcác thuộc tính và các thuộc tính khác.


4
Khi sử dụng vòng lặp for như vậy, keysẽ chỉ nhận một giá trị chỉ mục, do đó sẽ chỉ cảnh báo 0, 1, 2, v.v ... Bạn cần truy cập p [key].
Bryan

1
Đây là phương pháp lặp mảng chậm nhất trong JavaScript. Bạn có thể kiểm tra điều này trên máy tính của mình - Cách tốt nhất để lặp lại Mảng trong JavaScript
Pencroff

5
@Pencroff: vấn đề là câu hỏi không phải là về việc lặp qua các mảng ...;)
Sk8erPeter

Đây là điều tôi không hiểu trên stackoverflow. Richard đã đưa ra câu trả lời đúng, và anh ta là người đầu tiên đưa ra câu trả lời đó, nhưng anh ta không nhận được +1 nào? @Bryan var p = {"p1":"q","p2":"w"}; for(key in p) { alert( key ); }đang bật "p1" và "p2" trong các cảnh báo, vậy có gì sai về điều đó ???
Sebastian

5
Tôi nghĩ rằng sự khác biệt chính là chất lượng: các câu trả lời khác không chỉ cho biết làm thế nào, mà còn cho biết các cảnh báo (ví dụ, nguyên mẫu) và cách đối phó với những cảnh báo đó. IMHO, những câu trả lời khác tốt hơn so với tôi :).
Richard Levasseur

20

Sau khi xem qua tất cả các câu trả lời ở đây, hasOwnProperty không cần thiết cho việc sử dụng của riêng tôi vì đối tượng json của tôi sạch sẽ; thực sự không có ý nghĩa trong việc thêm bất kỳ xử lý javascript bổ sung. Đây là tất cả những gì tôi đang sử dụng:

for (var key in p) {
    console.log(key + ' => ' + p[key]);
    // key is key
    // value is p[key]
}

18
Việc đối tượng JSON có sạch hay không không liên quan. Nếu tại bất kỳ thời điểm nào khác, một số mã đặt thuộc tính Object.prototype, thì nó sẽ được liệt kê theo for..in. Nếu bạn chắc chắn rằng bạn không sử dụng bất kỳ thư viện nào làm điều đó, thì bạn không cần phải gọi hasOwnProperty.
G-Wiz

4
Nó có thể hoàn toàn sạch sẽ nếu được tạo ra vớiObject.create(null)
Juan Mendes

20

thông qua nguyên mẫu với forEach () sẽ bỏ qua các thuộc tính chuỗi nguyên mẫu :

Object.prototype.each = function(f) {
    var obj = this
    Object.keys(obj).forEach( function(key) { 
        f( key , obj[key] ) 
    });
}


//print all keys and values
var obj = {a:1,b:2,c:3}
obj.each(function(key,value) { console.log(key + " " + value) });
// a 1
// b 2
// c 3

2
Hãy cẩn thận với nguyên mẫu: obj = { print: 1, each: 2, word: 3 }sản xuất TypeError: number is not a function. Sử dụng forEachđể phù hợp với Arraychức năng tương tự có thể làm giảm rủi ro phần nào.
David Harkness

18

Những người thú vị trong những câu trả lời này đã chạm vào cả hai Object.keys()for...ofnhưng không bao giờ kết hợp chúng:

var map = {well:'hello', there:'!'};
for (let key of Object.keys(map))
    console.log(key + ':' + map[key]);

Bạn có thể không chỉ là for...ofmột Objectvì nó không phải là một iterator, và for...indexhoặc .forEach()ing Object.keys()là xấu xí / không hiệu quả.
Tôi rất vui vì hầu hết mọi người đang kiềm chế for...in(có hoặc không kiểm tra .hasOwnProperty()) vì điều đó cũng hơi lộn xộn, vì vậy ngoài câu trả lời của tôi ở trên, tôi ở đây để nói ...


Bạn có thể làm cho các hiệp hội đối tượng bình thường lặp đi lặp lại! Hành xử giống như Maps với việc sử dụng trực tiếp for...of
DEMO ưa thích hoạt động trong Chrome và FF (tôi chỉ giả sử ES6)

var ordinaryObject = {well:'hello', there:'!'};
for (let pair of ordinaryObject)
    //key:value
    console.log(pair[0] + ':' + pair[1]);

//or
for (let [key, value] of ordinaryObject)
    console.log(key + ':' + value);

Miễn là bạn bao gồm shim của tôi dưới đây:

//makes all objects iterable just like Maps!!! YAY
//iterates over Object.keys() (which already ignores prototype chain for us)
Object.prototype[Symbol.iterator] = function() {
    var keys = Object.keys(this)[Symbol.iterator]();
    var obj = this;
    var output;
    return {next:function() {
        if (!(output = keys.next()).done)
            output.value = [output.value, obj[output.value]];
        return output;
    }};
};

Không cần phải tạo một đối tượng Map thực sự không có đường cú pháp đẹp.

var trueMap = new Map([['well', 'hello'], ['there', '!']]);
for (let pair of trueMap)
    console.log(pair[0] + ':' + pair[1]);

Trên thực tế, với shim này, nếu bạn vẫn muốn tận dụng chức năng khác của Map (mà không làm mờ tất cả) nhưng vẫn muốn sử dụng ký hiệu đối tượng gọn gàng, vì giờ đây các đối tượng có thể lặp lại, bạn có thể tạo Bản đồ từ nó!

//shown in demo
var realMap = new Map({well:'hello', there:'!'});

Đối với những người không thích lung linh, hay prototypenói chung, hãy thoải mái thực hiện chức năng trên cửa sổ thay vào đó, gọi nó là một cái gì đó như getObjIterator()sau đó;

//no prototype manipulation
function getObjIterator(obj) {
    //create a dummy object instead of adding functionality to all objects
    var iterator = new Object();

    //give it what the shim does but as its own local property
    iterator[Symbol.iterator] = function() {
        var keys = Object.keys(obj)[Symbol.iterator]();
        var output;

        return {next:function() {
            if (!(output = keys.next()).done)
                output.value = [output.value, obj[output.value]];
            return output;
        }};
    };

    return iterator;
}

Bây giờ bạn chỉ có thể gọi nó là một chức năng bình thường, không có gì khác bị ảnh hưởng

var realMap = new Map(getObjIterator({well:'hello', there:'!'}))

hoặc là

for (let pair of getObjIterator(ordinaryObject))

Không có lý do tại sao điều đó sẽ không làm việc.

Chào mừng đến với tương lai.


1
Trường hợp tại điểm . Miễn là mọi người cuộn xuống và thấy nó hữu ích, đó mới là vấn đề. Thông thường, tôi đang cố gắng làm một cái gì đó, không thích những thứ tôi thấy trên mạng, cuối cùng tôi đã tìm ra nó, sau đó tôi quay lại để chia sẻ. Đó là tài liệu tốt, tôi thực sự đã đi qua câu trả lời của riêng mình trước khi googling những điều tôi hoàn toàn quên mất!
Hashbrown

@HelpMeStackOverflowMyOnlyITH Cá nhân tôi không thích sửa đổi các nguyên mẫu của các đối tượng mà tôi không tự xác định.
Janus Troelsen

@JanusTroelsen bạn thậm chí đã đọc toàn bộ câu trả lời? For those who don't like to shim, or mess with prototype in general, feel free to make the function on window instead, calling it something like getObjIterator() then;
Hashbrown

Lưu ý rằng kỹ thuật này không hoạt động trên các đối tượng đơn giản, nhưng dù sao cũng hữu ích.
noɥʇʎԀʎzɐɹƆ

nó hoạt động cho các đối tượng đơn giản, nghĩa đen là toàn bộ điểm (cũng như các tên biến như ordinaryObjectnhấn mạnh rằng ma thuật vẫn hoạt động cho các loại đó). Bạn đã kiểm tra các bản demo; những gì không làm việc cho bạn, @ noɥʇʎԀʎzɐɹƆ? (PS hình ảnh hồ sơ SE của bạn là ông chủ)
Hashbrown

13

Object.keys (obj): Mảng

lấy tất cả các khóa có giá trị chuỗi của tất cả các thuộc tính riêng (không được kế thừa).

Vì vậy, nó đưa ra danh sách các khóa giống như bạn dự định bằng cách kiểm tra từng khóa đối tượng với hasOwnProperty. Bạn không cần thao tác kiểm tra thêm đó và Object.keys( obj ).forEach(function( key ){})được cho là nhanh hơn. Hãy chứng minh điều đó:

var uniqid = function(){
			var text = "",
					i = 0,
					possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
			for( ; i < 32; i++ ) {
					text += possible.charAt( Math.floor( Math.random() * possible.length ) );
			}
			return text;
		}, 
		CYCLES = 100000,
		obj = {}, 
		p1,
		p2,
		p3,
		key;

// Populate object with random properties
Array.apply( null, Array( CYCLES ) ).forEach(function(){
	obj[ uniqid() ] = new Date()
});

// Approach #1
p1 = performance.now();
Object.keys( obj ).forEach(function( key ){
	var waste = obj[ key ];
});

p2 = performance.now();
console.log( "Object.keys approach took " + (p2 - p1) + " milliseconds.");

// Approach #2
for( key in obj ) {
	if ( obj.hasOwnProperty( key ) ) {
		var waste = obj[ key ];
	}
}

p3 = performance.now();
console.log( "for...in/hasOwnProperty approach took " + (p3 - p2) + " milliseconds.");

Trong Firefox của tôi, tôi có kết quả như sau

  • Cách tiếp cận Object.keys mất 40.21101451665163 mili giây.
  • cho ... trong / hasOwnProperty cách tiếp cận mất 98,26163508463651 mili giây.

Tái bút trên Chrome sự khác biệt thậm chí còn lớn hơn http://codepen.io/dsheiko/pen/JdrqXa

PS2: Trong ES6 (EcmaScript 2015), bạn có thể lặp lại đối tượng lặp lại đẹp hơn:

let map = new Map().set('a', 1).set('b', 2);
for (let pair of map) {
    console.log(pair);
}

// OR 
let map = new Map([
    [false, 'no'],
    [true,  'yes'],
]);
map.forEach((value, key) => {
    console.log(key, value);
});


nếu bạn không muốn bỏ ký hiệu {}, bạn vẫn có thể sử dụng of mà không cần tạo Maps
Hashbrown

13

Đây là một phương pháp khác để lặp qua một đối tượng.

   var p = {
"p1": "value1",
"p2": "value2",
"p3": "value3"
};


Object.keys(p).forEach(key => { console.log(key, p[key]) })


3
Điều này khá tuyệt, tuy nhiên đối với các đối tượng lớn, forphương thức có thể hiệu quả hơn.
Rolf

13

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

for (var key in p) {
    if (p.hasOwnProperty(key)) {
        console.log(key + " = " + p[key]);
    }
}
<p>
  Output:<br>
  p1 = values1<br>
  p2 = values2<br>
  p3 = values3
</p>


12

Bạn cũng có thể sử dụng Object.keys () và lặp lại các khóa đối tượng như bên dưới để nhận giá trị:

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

Object.keys(p).forEach((key)=> {
 console.log(key +' -> '+ p[key]);
});


Bạn đã tiết kiệm thời gian của tôi, Cảm ơn bạn
Hoán đổi-IOS-Android

Rất vui được biết :)
Onera

8

Chỉ mã JavaScript không có phụ thuộc:

var p = {"p1": "value1", "p2": "value2", "p3": "value3"};
keys = Object.keys(p);   // ["p1", "p2", "p3"]

for(i = 0; i < keys.length; i++){
  console.log(keys[i] + "=" + p[keys[i]]);   // p1=value1, p2=value2, p3=value3
}

8

Các Object.keys()phương thức trả về một mảng các thuộc tính đếm được của một đối tượng nhất định của. Tìm hiểu thêm về nó ở đây

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

Object.keys(p).map((key)=> console.log(key + "->" + p[key]))


8

Hiệu suất

Hôm nay 2020.03.06 Tôi thực hiện kiểm tra các giải pháp được chọn trên Chrome v80.0, Safari v13.0.5 và Firefox 73.0.1 trên MacOs High Sierra v10.13.6

Kết luận

  • các giải pháp dựa trên for-in(A, B) là nhanh (hoặc nhanh nhất) cho tất cả các trình duyệt cho các đối tượng lớn và nhỏ
  • đáng ngạc nhiên for-oflà giải pháp (H) nhanh chóng trên chrome cho các đối tượng nhỏ và lớn
  • giải pháp dựa trên chỉ số rõ ràng i (J, K) khá nhanh trên tất cả các trình duyệt cho các đối tượng nhỏ (đối với firefox cũng nhanh đối với các ojbects lớn nhưng trung bình nhanh trên các trình duyệt khác)
  • các giải pháp dựa trên các trình vòng lặp (D, E) là chậm nhất và không được đề xuất
  • dung dịch C chậm đối với vật lớn và chậm trung bình đối với vật nhỏ

nhập mô tả hình ảnh ở đây

Chi tiết

Kiểm tra hiệu suất đã được thực hiện cho

  • đối tượng nhỏ - với 3 trường - bạn có thể thực hiện kiểm tra trên máy của mình TẠI ĐÂY
  • Đối tượng 'lớn' - với 1000 trường - bạn có thể thực hiện kiểm tra trên máy của mình TẠI ĐÂY

Đoạn trích dưới đây trình bày các giải pháp được sử dụng

Và đây là kết quả cho các đối tượng nhỏ trên chrome

nhập mô tả hình ảnh ở đây


7

Bạn có thể thêm một hàm forEach đơn giản cho tất cả các đối tượng, để bạn có thể tự động lặp qua bất kỳ đối tượng nào:

Object.defineProperty(Object.prototype, 'forEach', {
    value: function (func) {
        for (var key in this) {
            if (!this.hasOwnProperty(key)) {
                // skip loop if the property is from prototype
                continue;
            }
            var value = this[key];
            func(key, value);
        }
    },
    enumerable: false
});

Đối với những người không thích " cho ... trong " -method:

Object.defineProperty(Object.prototype, 'forEach', {
    value: function (func) {
        var arr = Object.keys(this);
        for (var i = 0; i < arr.length; i++) {
            var key = arr[i];
            func(key, this[key]);
        }
    },
    enumerable: false
});

Bây giờ, bạn có thể gọi đơn giản:

p.forEach (function(key, value){
    console.log ("Key: " + key);
    console.log ("Value: " + value);
});

Nếu bạn không muốn bị xung đột với các Phương pháp forEach khác, bạn có thể đặt tên cho nó bằng tên duy nhất của bạn.


3
Sửa đổi các nguyên mẫu của các đối tượng được xây dựng (như Object) thường được coi là một mẫu chống vì nó có thể dễ dàng gây ra xung đột với các mã khác. Vì vậy, vết thương không khuyên bạn nên làm theo cách này.
Moritz

6

Vòng lặp có thể khá thú vị khi sử dụng JavaScript thuần túy. Có vẻ như chỉ ECMA6 (đặc tả JavaScript mới 2015) có các vòng lặp được kiểm soát. Thật không may khi tôi viết bài này, cả Trình duyệt và môi trường phát triển tích hợp (IDE) phổ biến vẫn đang vật lộn để hỗ trợ hoàn toàn tiếng chuông và còi mới.

Nhìn thoáng qua đây là một vòng lặp đối tượng JavaScript trông như thế nào trước ECMA6:

for (var key in object) {
  if (p.hasOwnProperty(key)) {
    var value = object[key];
    console.log(key); // This is the key;
    console.log(value); // This is the value;
  }
}

Ngoài ra, tôi biết điều này nằm ngoài phạm vi của câu hỏi này, nhưng vào năm 2011, ECMAScript 5.1 đã thêm forEachphương thức cho Mảng chỉ về cơ bản tạo ra một cách cải tiến mới để lặp qua các mảng trong khi vẫn để các đối tượng không lặp lại với forvòng lặp dài và khó hiểu cũ . Nhưng phần kỳ lạ là forEachphương pháp mới này không hỗ trợ breakdẫn đến tất cả các loại vấn đề khác.

Về cơ bản vào năm 2011, không có một cách chắc chắn nào để lặp lại trong JavaScript ngoài những gì mà nhiều thư viện phổ biến (jQuery, Underscore, v.v.) đã quyết định triển khai lại.

Kể từ năm 2015, giờ đây chúng ta đã có cách tốt hơn để lặp (và phá vỡ) bất kỳ loại đối tượng nào (bao gồm Mảng và Chuỗi). Đây là vòng lặp trong JavaScript cuối cùng sẽ trông như thế nào khi đề xuất trở thành chính:

for (let [key, value] of Object.entries(object)) {
    console.log(key); // This is the key;
    console.log(value); // This is the value;
}

Lưu ý rằng hầu hết các trình duyệt sẽ không hỗ trợ mã ở trên kể từ ngày 18 tháng 6 năm 2016. Ngay cả trong Chrome, bạn cần bật cờ đặc biệt này để nó hoạt động: chrome://flags/#enable-javascript-harmony

Cho đến khi điều này trở thành tiêu chuẩn mới, phương thức cũ vẫn có thể được sử dụng nhưng cũng có những lựa chọn thay thế trong các thư viện phổ biến hoặc thậm chí là các lựa chọn thay thế nhẹ cho những người không sử dụng bất kỳ thư viện nào trong số này.


Bạn có thể cung cấp một fiddle của công việc này? Đây là nỗ lực của tôi. jsfiddle.net/abalter/sceeb211
abalter

@abalter Xin lỗi tôi nhận ra tôi có một lỗi đánh máy trong mã của mình. Tôi đã sửa nó và cập nhật JsFiddle của bạn tại đây: jsfiddle.net/sceeb211/2
Nicolas Bouvrette

Tôi đang ở trong chrome và nhận được Uncaught TypeError: Object.entries is not a function. Nó chưa được thực hiện trong chrome chưa?
abalter

@abalter Đó là. Đảm bảo bạn có Chrome phiên bản 51 và bạn đã bật cờ như được giải thích trong các nhận xét chỉnh sửa và Jsfiddle của tôi. Bạn có thể kiểm tra các chi tiết tại đây: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/
trộm

Xin lỗi tôi đã bỏ lỡ điều đó về cờ. Tôi thấy nó chưa phải là một tính năng được thực hiện đầy đủ.
abalter

5

Trong ES6, chúng ta có các biểu tượng nổi tiếng để hiển thị một số phương thức bên trong trước đó, bạn có thể sử dụng nó để xác định cách các trình lặp hoạt động cho đối tượng này:

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3",
    *[Symbol.iterator]() {
        yield *Object.keys(this);
    }
};

[...p] //["p1", "p2", "p3"]

điều này sẽ cho kết quả tương tự như khi sử dụng cho ... trong vòng lặp es6.

for(var key in p) {
    console.log(key);
}

Nhưng điều quan trọng là phải biết các khả năng mà bạn hiện đang sử dụng es6!


1
Trình lặp đối tượng tùy chỉnh gọi trình lặp mảng tích hợp của một mảng được tạo Object.keys()và phân bổ trong bộ nhớ ... Tuyệt!
ooo

5

Tôi sẽ làm điều này hơn là kiểm tra obj.hasOwnerPropertytrong mỗi for ... invòng lặp.

var obj = {a : 1};
for(var key in obj){
    //obj.hasOwnProperty(key) is not needed.
    console.log(key);
}
//then check if anybody has messed the native object. Put this code at the end of the page.
for(var key in Object){
    throw new Error("Please don't extend the native object");
}

5

    var p =[{"username":"ordermanageadmin","user_id":"2","resource_id":"Magento_Sales::actions"},
{"username":"ordermanageadmin_1","user_id":"3","resource_id":"Magento_Sales::actions"}]
for(var value in p) {
    for (var key in value) {
        if (p.hasOwnProperty(key)) {
            console.log(key + " -> " + p[key]);
        }
    }
}


json = [{"key1":"value1","key2":"value2"},{"key1":"value3","key2":"value4"}] for (var i = 0; i < json.length; i++) { for (var key in json[i]) { if (json[i].hasOwnProperty(key)) { console.log(key + " -> " + json[i][key]); } } }
Marek Bernád

5

Sử dụng một for-oftrênObject.keys()

Giống:

let object = {
   "key1": "value1"
   "key2": "value2"
   "key3": "value3"
};

for (var key of Object.keys(p)) {
   console.log(key + " : " + object[key])
}

4

Nếu bạn cũng muốn lặp lại các thuộc tính không thể đếm được , bạn có thể sử dụng Object.getOwnPropertyNames(obj)để trả về một mảng của tất cả các thuộc tính (liệt kê hoặc không) được tìm thấy trực tiếp trên một đối tượng nhất định.

var obj = Object.create({}, {
  // non-enumerable property
  getFoo: {
    value: function() { return this.foo; },
    enumerable: false
  }
});

obj.foo = 1; // enumerable property

Object.getOwnPropertyNames(obj).forEach(function (name) {
  document.write(name + ': ' + obj[name] + '<br/>');
});


2
Điều này thật tuyệt vời, cảm ơn bạn đã đăng câu trả lời này. Tôi cần phải hướng nội một Errorđối tượng và không thể có được các thuộc tính trong một vòng lặp hoặc một _.forIn(err)cuộc gọi. Việc sử dụng Object.getOwnPropertyNames(err)cho phép tôi truy cập tất cả các phần Errormà trước đây tôi không thể có được. Cảm ơn!
Pierce

4

Nếu bất cứ ai cần lặp qua mảngObjects với điều kiện :

var arrayObjects = [{"building":"A", "status":"good"},{"building":"B","status":"horrible"}];

for (var i=0; i< arrayObjects.length; i++) {
  console.log(arrayObjects[i]);
  
  for(key in arrayObjects[i]) {      
    
      if (key == "status" && arrayObjects[i][key] == "good") {
        
          console.log(key + "->" + arrayObjects[i][key]);
      }else{
          console.log("nothing found");
      }
   }
}


4

Xem xét ES6 tôi muốn thêm muỗng đường của riêng mình và cung cấp thêm một cách tiếp cận để lặp lại các thuộc tính của đối tượng.

Vì đối tượng JS đơn giản không thể lặp lại ngay lập tức, chúng tôi không thể sử dụng for..ofvòng lặp để lặp lại nội dung của nó. Nhưng không ai có thể ngăn chúng tôi làm cho nó lặp đi lặp lại .

Chúng ta hãy có bookđối tượng.

let book = {
  title: "Amazing book",
  author: "Me",
  pages: 3
}

book[Symbol.iterator] = function(){

  let properties = Object.keys(this); // returns an array with property names
  let counter = 0;
  let isDone = false;

  let next = () => {
    if(counter >= properties.length){
      isDone = true;
    }
    return { done: isDone, value: this[properties[counter++]] }
  }

  return { next };
}

Vì chúng tôi đã tạo ra nó, chúng tôi có thể sử dụng nó theo cách này:

for(let pValue of book){
  console.log(pValue);
}
------------------------
Amazing book
Me
3

Hoặc nếu bạn biết sức mạnh của các trình tạo ES6 , vì vậy bạn chắc chắn có thể làm cho mã trên ngắn hơn nhiều.

book[Symbol.iterator] = function *(){

  let properties = Object.keys(this);
  for (let p of properties){
    yield this[p];
  }

}

Chắc chắn, bạn có thể áp dụng hành vi như vậy cho tất cả các đối tượng với việc Objectlặp lại theo prototypecấp độ.

Object.prototype[Symbol.iterator] = function() {...}

Ngoài ra, các đối tượng tuân thủ giao thức lặp có thể được sử dụng với toán tử trải rộng tính năng ES2015 mới, do đó chúng ta có thể đọc các giá trị thuộc tính đối tượng dưới dạng một mảng.

let pValues = [...book];
console.log(pValues);
-------------------------
["Amazing book", "Me", 3]

Hoặc bạn có thể sử dụng chuyển nhượng hủy :

let [title, , pages] = book; // notice that we can just skip unnecessary values
console.log(title);
console.log(pages);
------------------
Amazing book
3

Bạn có thể kiểm tra JSFiddle với tất cả mã tôi đã cung cấp ở trên.


Tôi tìm thấy mã sẽ tạo ra các giá trị nhưng không có khóa. Có thể lặp lại các giá trị với các khóa?
Pika

Vâng, bạn có thể. Chỉ cần trả về "suất [khóa, obj [khóa]];" từ chức năng trình tạo của bạn và sau đó sử dụng nó như sau "for (let [key, value] of {}) {}"
Artyom Pranovich

4

kể từ ES06, bạn có thể lấy các giá trị của một đối tượng dưới dạng mảng với

let arrValues = Object.values( yourObject) ;

nó trả về một mảng các giá trị đối tượng và nó không trích xuất các giá trị từ Prototype !!

Đối tượng MDN DOCS.values ​​()

và cho các khóa (tất cả đã trả lời trước khi tôi ở đây)

let arrKeys   = Object.keys(yourObject);

Các câu trả lời yêu cầu một giải pháp trả về cả khóa và giá trị.
Sean Lindo

4

Trong tập lệnh ES mới nhất, bạn có thể làm một cái gì đó như thế này:

let p = {foo: "bar"};
for (let [key, value] of Object.entries(p)) {
  console.log(key, value);
}

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.