Lặp qua một mảng trong JavaScript


3146

Trong Java, bạn có thể sử dụng một forvòng lặp để duyệt qua các đối tượng trong một mảng như sau:

String[] myStringArray = {"Hello", "World"};
for (String s : myStringArray)
{
    // Do something
}

Bạn có thể làm tương tự trong JavaScript không?


5
Ok, vì vậy tôi hơi bối rối, có thể sử dụng vòng lặp nâng cao khi bạn truy cập vào các đối tượng không? Và sử dụng một tuần tự để điền vào một? Điều này có đúng không?
Mark Szymanski

45
không, nó thực sự đơn giản, các đối tượng mảng có các chỉ mục số, vì vậy bạn muốn lặp lại các chỉ mục đó theo thứ tự số, một vòng tuần tự đảm bảo rằng, vòng lặp nâng cao liệt kê các thuộc tính đối tượng, không có thứ tự cụ thể và nó cũng liệt kê các thuộc tính được kế thừa. .. để lặp đi lặp lại trên các mảng, các vòng lặp tuần tự luôn được khuyến nghị ...for-in
CMS


6
jsben.ch/#/Q9oD5 <= Dưới đây là điểm chuẩn của một loạt các giải pháp để lặp qua các mảng
EscapeNetscape

3
@CMS Không, nó không thực sự đơn giản. Nó thực sự đơn giản trong mọi ngôn ngữ khác. Nó phức tạp một cách lố bịch trong JS, nơi bạn có inofcả hai có thể được sử dụng và làm những việc khác nhau. Sau đó, bạn cũng có forEachvà vòng lặp dựa trên chỉ số xấu xí và gây phiền nhiễu. Mỗi ngôn ngữ hiện đại khác làm cho việc lặp lại một bộ sưu tập dễ dàng và đơn giản mà không có bất ngờ hoặc nhầm lẫn. JS cũng có thể, nhưng nó không.
jpmc26

Câu trả lời:


3963

Bạn có một vài lựa chọn:

1. forVòng lặp tuần tự :

var myStringArray = ["Hello","World"];
var arrayLength = myStringArray.length;
for (var i = 0; i < arrayLength; i++) {
    console.log(myStringArray[i]);
    //Do something
}

Ưu

  • Hoạt động trên mọi môi trường
  • Bạn có thể sử dụng breakcontinueđiều khiển luồng báo cáo

Nhược điểm

  • Quá dài dòng
  • Bắt buộc
  • Dễ có lỗi do lỗi (đôi khi còn được gọi là lỗi hàng rào )

2. Array.prototype.forEach

Đặc tả ES5 đã giới thiệu rất nhiều phương thức mảng có lợi, một trong số đó, Array.prototype.forEachvà nó cho chúng ta một cách ngắn gọn để lặp lại qua một mảng:

const array = ["one", "two", "three"]
array.forEach(function (item, index) {
  console.log(item, index);
});

Gần mười năm kể từ thời điểm viết đặc tả ES5 được phát hành (tháng 12 năm 2009), nó đã được thực hiện bởi hầu hết các động cơ hiện đại trong máy tính để bàn, máy chủ và môi trường di động, vì vậy an toàn khi sử dụng chúng.

Và với cú pháp hàm mũi tên ES6, nó thậm chí còn ngắn gọn hơn:

array.forEach(item => console.log(item));

Các chức năng mũi tên cũng được triển khai rộng rãi trừ khi bạn có kế hoạch hỗ trợ các nền tảng cổ xưa (ví dụ: IE11); bạn cũng an toàn để đi

Ưu

  • Rất ngắn gọn và súc tích.
  • Tuyên bố

Nhược điểm

  • Không thể sử dụng break/continue

Thông thường, bạn có thể thay thế nhu cầu breakthoát khỏi các vòng lặp bắt buộc bằng cách lọc các phần tử mảng trước khi lặp lại chúng, ví dụ:

array.filter(item => item.condition < 10)
     .forEach(item => console.log(item))

Hãy ghi nhớ nếu bạn đang lặp lại một mảng để xây dựng một mảng khác từ nó , bạn nên sử dụng map, tôi đã thấy mô hình chống này rất nhiều lần.

Chống mẫu:

const numbers = [1,2,3,4,5], doubled = [];

numbers.forEach((n, i) => { doubled[i] = n * 2 });

Trường hợp sử dụng đúng của bản đồ :

const numbers = [1,2,3,4,5];
const doubled = numbers.map(n => n * 2);

console.log(doubled);

Ngoài ra, nếu bạn đang cố gắng giảm mảng đến một giá trị, ví dụ, bạn muốn tổng hợp một loạt các con số, bạn nên sử dụng giảm phương pháp.

Chống mẫu:

const numbers = [1,2,3,4,5];
const sum = 0;
numbers.forEach(num => { sum += num });

Sử dụng đúng cách giảm :

const numbers = [1,2,3,4,5];
const sum = numbers.reduce((total, n) => total + n, 0);

console.log(sum);

3. for-ofTuyên bố ES6

Tiêu chuẩn ES6 giới thiệu khái niệm về các đối tượng có thể lặp lại và định nghĩa một cấu trúc mới để truyền tải dữ liệu, for...ofcâu lệnh.

Tuyên bố này hoạt động cho bất kỳ loại đối tượng lặp lại và cho cả các trình tạo (bất kỳ đối tượng nào có thuộc [Symbol.iterator]tính).

Các đối tượng mảng theo định nghĩa iterables tích hợp trong ES6, vì vậy bạn có thể sử dụng câu lệnh này trên chúng:

let colors = ['red', 'green', 'blue'];
for (const color of colors){
    console.log(color);
}

Ưu

  • Nó có thể lặp đi lặp lại trên một loạt các đối tượng.
  • Có thể sử dụng báo cáo kiểm soát dòng chảy bình thường ( break/ continue).
  • Hữu ích để lặp lại các giá trị không đồng bộ ser seri.

Nhược điểm

Không được dùng for...in

@zipcodeman đề xuất sử dụng for...incâu lệnh, nhưng để for-intránh các mảng lặp, nên tránh câu lệnh đó để liệt kê các thuộc tính đối tượng.

Nó không nên được sử dụng cho các đối tượng giống như mảng bởi vì:

  • Thứ tự lặp không được đảm bảo; các chỉ mục mảng có thể không được truy cập theo thứ tự số.
  • Tài sản thừa kế cũng được liệt kê.

Điểm thứ hai là nó có thể cung cấp cho bạn rất nhiều vấn đề, ví dụ, nếu bạn mở rộng Array.prototypeđối tượng để bao gồm một phương thức ở đó, thuộc tính đó cũng sẽ được liệt kê.

Ví dụ:

Array.prototype.foo = "foo!";
var array = ['a', 'b', 'c'];

for (var i in array) {
    console.log(array[i]);
}

Đoạn mã trên sẽ điều khiển đăng nhập "a", "b", "c" và "foo!".

Điều đó đặc biệt là một vấn đề nếu bạn sử dụng một số thư viện phụ thuộc nhiều vào việc tăng nguyên mẫu gốc (chẳng hạn như MooTools chẳng hạn).

Câu for-inlệnh như tôi đã nói trước đây là để liệt kê các thuộc tính đối tượng, ví dụ:

var obj = {
    "a": 1,
    "b": 2,
    "c": 3
};

for (var prop in obj) {
    if (obj.hasOwnProperty(prop)) { 
        // or if (Object.prototype.hasOwnProperty.call(obj,prop)) for safety...
        console.log("prop: " + prop + " value: " + obj[prop])
    }
}

Trong ví dụ trên, hasOwnPropertyphương thức cho phép bạn liệt kê chỉ các thuộc tính , đó là nó, chỉ các thuộc tính mà vật thể có, không có thuộc tính được thừa kế.

Tôi muốn giới thiệu bạn đọc bài viết sau:


21
Đây là lý do (bởi chính anh ấy là CMS) stackoverflow.com/questions/1885317/ trên
OscarRyz

15
@DoubleGras, tôi nghĩ đó là một ý kiến ​​không được mọi người chia sẻ. Xem: stackoverflow.com/questions/5752906/nhóm.google.com/forum/?fromgroups
Matthijs Wessels

3
Bất cứ ai nghĩ rằng bạn cần lưu trữ độ dài ... Xin vui lòng xem câu trả lời của tôi, bạn thậm chí không cần truy cập nó một lần, chứ đừng nói đến bộ đệm đó: for (var i = 0, item; item = myStringArray [i]; i ++) {/ * sử dụng vật phẩm tại đây * /}
Stijn de Witt

15
@StijndeWitt Không, bởi vì nghỉ rằng nếu bạn có bất kỳ "falsey" giá trị trong mảng của bạn: false, undefined, 0, "", NaN.
Phrogz

6
jsperf.com/caching-array-length/4 Đây là một thử nghiệm để xem có đáng lưu vào bộ nhớ cache độ dài của một mảng trong một vòng lặp Javascript hay không
Enrico

1114

Có, giả sử việc triển khai của bạn bao gồm for...of tính năng được giới thiệu trong ECMAScript 2015 (bản phát hành "Hài hòa") ... đây là một giả định khá an toàn trong những ngày này.

Nó hoạt động như thế này:

// REQUIRES ECMASCRIPT 2015+
var s, myStringArray = ["Hello", "World"];
for (s of myStringArray) {
  // ... do something with s ...
}

Hoặc tốt hơn nữa, vì ECMAScript 2015 cũng cung cấp các biến trong phạm vi khối:

// REQUIRES ECMASCRIPT 2015+
const myStringArray = ["Hello", "World"];
for (const s of myStringArray) {
  // ... do something with s ...
}
// s is no longer defined here

(Biến slà khác nhau trên mỗi lần lặp, nhưng vẫn có thể được khai báo constbên trong thân vòng lặp miễn là nó không được sửa đổi ở đó.)

Một lưu ý về mảng thưa thớt: một mảng trong JavaScript có thể không thực sự lưu trữ nhiều mục như báo cáo của nó length; số báo cáo đó chỉ đơn giản là một số lớn hơn chỉ số cao nhất mà tại đó một giá trị được lưu trữ. Nếu mảng chứa ít phần tử hơn chỉ định bởi độ dài của nó, thì nó được gọi là thưa thớt . Ví dụ: hoàn toàn hợp pháp khi có một mảng với các mục chỉ ở các chỉ mục 3, 12 và 247; các lengthcủa một mảng như vậy được báo cáo là 248, mặc dù nó chỉ thực sự lưu trữ 3 giá trị. Nếu bạn cố gắng truy cập một mục tại bất kỳ chỉ mục nào khác, mảng sẽ xuất hiện để có undefinedgiá trị ở đó. Vì vậy, khi bạn muốn "lặp qua" một mảng, bạn có một câu hỏi cần trả lời: bạn có muốn lặp lại toàn bộ phạm vi được chỉ định bởi độ dài và quy trình của nó khôngundefined s cho bất kỳ yếu tố mất tích, hay bạn chỉ muốn xử lý các yếu tố thực tế hiện nay? Có rất nhiều ứng dụng cho cả hai phương pháp; nó chỉ phụ thuộc vào những gì bạn đang sử dụng mảng cho.

Nếu bạn lặp qua một mảng với for.. of, phần thân của vòng lặp được thực hiện lengthlần và biến điều khiển vòng lặp được đặt thành undefinedcho bất kỳ mục nào không thực sự có trong mảng. Tùy thuộc vào chi tiết mã "làm điều gì đó với" của bạn, hành vi đó có thể là điều bạn muốn, nhưng nếu không, bạn nên sử dụng một cách tiếp cận khác.

Tất nhiên, một số nhà phát triển không có lựa chọn nào khác để sử dụng một cách tiếp cận khác nhau dù sao, bởi vì đối với bất cứ lý do họ đang nhắm mục tiêu một phiên bản của JavaScript mà chưa hỗ trợ for... of.

Miễn là việc triển khai JavaScript của bạn tuân thủ phiên bản trước của đặc tả ECMAScript (ví dụ: loại trừ các phiên bản của Internet Explorer trước 9), thì bạn có thể sử dụng Array#forEachphương thức lặp thay vì vòng lặp. Trong trường hợp đó, bạn truyền một hàm được gọi trên mỗi mục trong mảng:

var myStringArray = [ "Hello", "World" ];
myStringArray.forEach( function(s) { 
     // ... do something with s ...
} );

Không giống như for... of, .forEachchỉ gọi hàm cho các phần tử thực sự có trong mảng. Nếu vượt qua mảng giả thuyết của chúng tôi với ba phần tử và độ dài là 248, nó sẽ chỉ gọi hàm ba lần, không phải là 248 lần. Nó cũng phân biệt giữa các yếu tố bị thiếu và các yếu tố thực sự được đặt thành undefined; đối với cái sau, nó vẫn sẽ gọi hàm, truyền undefinedlàm đối số. Nếu đây là cách bạn muốn xử lý mảng thưa thớt, .forEachcó thể là cách để đi ngay cả khi hỗ trợ thông dịch viên của bạn for... of.

Tùy chọn cuối cùng, hoạt động trong tất cả các phiên bản JavaScript, là một vòng lặp đếm rõ ràng . Bạn chỉ cần đếm từ 0 đến một ít hơn một chiều dài và sử dụng bộ đếm làm chỉ mục. Vòng lặp cơ bản trông như thế này:

var i, s, myStringArray = [ "Hello", "World" ], len = myStringArray.length;
for (i=0; i<len; ++i) {
  s = myStringArray[i];
  // ... do something with s ...
}

Một lợi thế của phương pháp này là bạn có thể chọn cách xử lý các mảng thưa thớt; các mã trên sẽ chạy phần thân của vòng lặp toàn bộ lengththời gian, với scác thiết lập để undefinedcho bất kỳ yếu tố mất tích, giống như for.. of. Thay vào đó, nếu bạn chỉ muốn xử lý các phần tử hiện tại thực sự của một mảng thưa thớt .forEach, bạn có thể thêm một inbài kiểm tra đơn giản vào chỉ mục:

var i, s, myStringArray = [ "Hello", "World" ], len = myStringArray.length;
for (i=0; i<len; ++i) {
  if (i in myStringArray) {
    s = myStringArray[i];
    // ... do something with s ...
  }
}

Việc gán giá trị độ dài cho biến cục bộ (trái ngược với việc bao gồm myStringArray.lengthbiểu thức đầy đủ trong điều kiện vòng lặp) có thể tạo ra sự khác biệt đáng kể về hiệu suất do nó bỏ qua một tra cứu thuộc tính mỗi lần đi qua; sử dụng Rhino trên máy của tôi, tốc độ tăng lên là 43%.

Bạn có thể thấy bộ nhớ đệm dài được thực hiện trong mệnh đề khởi tạo vòng lặp, như sau:

var i, len, myStringArray = [ "Hello", "World" ];
for (len = myStringArray.length, i=0; i<len; ++i) {

Vòng lặp đếm rõ ràng cũng có nghĩa là bạn có quyền truy cập vào chỉ mục của từng giá trị, nếu bạn muốn nó. Chỉ mục cũng được truyền dưới dạng tham số bổ sung cho hàm bạn truyền đến forEach, vì vậy bạn cũng có thể truy cập theo cách đó:

myStringArray.forEach( function(s, i) {
   // ... do something with s and i ...
});

for... ofkhông cung cấp cho bạn chỉ mục được liên kết với từng đối tượng, nhưng miễn là đối tượng bạn lặp đi lặp lại thực sự là một Array( for.. ofhoạt động cho các loại lặp khác có thể không có phương thức này), bạn có thể sử dụng Mảng Phương thức #entries để thay đổi nó thành một mảng các cặp [index, item] và sau đó lặp lại qua đó:

for (const [i, s] of myStringArray.entries()) {
  // ... do something with s and i ...
}

Các for... incú pháp được đề cập bởi những người khác là cho Looping qua thuộc tính của một đối tượng; vì một mảng trong JavaScript chỉ là một đối tượng có tên thuộc tính số (và thuộc tính được cập nhật tự động length), về mặt lý thuyết bạn có thể lặp qua một mảng với nó. Nhưng vấn đề là nó không tự giới hạn các giá trị thuộc tính số (hãy nhớ rằng các phương thức thậm chí thực sự chỉ là các thuộc tính có giá trị là một bao đóng), và cũng không được đảm bảo lặp lại các giá trị theo thứ tự số. Do đó, cú pháp for... khôngin nên được sử dụng để lặp qua Mảng.


21
Lưu ý rằng một số trình thông dịch (ví dụ V8) sẽ tự động lưu trữ độ dài của mảng nếu mã được gọi đủ số lần và nó phát hiện ra rằng độ dài không được sửa đổi bởi vòng lặp. Mặc dù bộ nhớ đệm có độ dài vẫn tốt, nhưng nó có thể không tăng tốc khi mã của bạn được gọi đủ số lần để thực sự tạo ra sự khác biệt.
Phrogz

2
@ mark-reed Bạn có thể giải thích lý do tại sao bạn sử dụng i in myStringArraytrong ví dụ của mình không? Làm thế nào điều đó có thể là sai?
Denis V

2
@DenisV: sai. a=[1,2,3,4]; delete a[2]; for (j in a) { console.log(j); } đầu ra 0, 1, 3 và 4. a.lengthvẫn là 5.
Mark Reed

1
Tôi không gợi ý for j in a. Tôi đang chứng minh rằng inséc không dư thừa, như bạn đã tuyên bố, bằng cách hiển thị tất cả các chỉ mục và hiển thị rằng có một trong số 0 và length-1không có ở đó. Tôi cũng có thể vừa in 2 in a, điều đó thực sự false, mặc dù thực tế là bạn nói rằng điều đó là không thể.
Mark Reed

2
@GrijeshChauhan - đúng. Chẳng hạn, IE đến phiên bản 8 không hỗ trợ. Xem câu hỏi này .
Mark Reed

442

Bạn có thể sử dụng map, đây là một kỹ thuật lập trình chức năng cũng có sẵn trong các ngôn ngữ khác như PythonHaskell .

[1,2,3,4].map( function(item) {
     alert(item);
})

Cú pháp chung là:

array.map(func)

Nói chung funcsẽ có một tham số, đó là một mục của mảng. Nhưng trong trường hợp JavaScript, nó có thể lấy tham số thứ hai là chỉ mục của mục và tham số thứ ba là chính mảng đó.

Giá trị trả về của array.mapmột mảng khác, vì vậy bạn có thể sử dụng nó như thế này:

var x = [1,2,3,4].map( function(item) {return item * 10;});

Và bây giờ x là [10,20,30,40].

Bạn không phải viết hàm nội tuyến. Nó có thể là một chức năng riêng biệt.

var item_processor = function(item) {
      // Do something complicated to an item
}

new_list = my_list.map(item_processor);

tương đương với:

 for (item in my_list) {item_processor(item);}

Ngoại trừ bạn không nhận được new_list.


7
Không, nhưng nó có thể mạnh hơn. kiểm tra cái này: joelonsoftware.com/items/2006/08/01.html
hasen

97
Ví dụ cụ thể đó có lẽ được thực hiện tốt hơn bằng cách sử dụng Array.forEach. maplà để tạo ra một mảng mới.
harto

21
@ Hasen, các Array.prototype.mapphương pháp là một phần của ECMAScript 5 Standard Edition, chưa có sẵn trên tất cả các triển khai (ví dụ IE thiếu của nó), cũng cho iterating trên một mảng Tôi nghĩ rằng Array.prototype.forEachphương pháp là hơn ngữ nghĩa chính xác ... cũng xin vui lòng don' t đề xuất tuyên bố for-in, xem câu trả lời của tôi để biết thêm chi tiết :)
CMS

3
Sự khác biệt giữa forEachmaplà cái trước không trả về kết quả của phép lặp. map(đôi khi aka collect, nhưng rất khác với apply) rõ ràng là để chuyển đổi từng phần tử của một mảng thành một kết quả tương ứng; đó là ánh xạ 1 đến 1 , do đó có tên. Đó là một phần của cả một nhóm các hoạt động bao gồm reduce(tạo ra một kết quả duy nhất từ ​​toàn bộ mảng) và filter(tạo ra một tập hợp con của mảng ban đầu), v.v. Trong khi forEachchỉ cần làm một cái gì đó với từng yếu tố, ngữ nghĩa không xác định.
Mark Reed

4
Downvote bởi vì nếu bạn không thực sự ánh xạ một cái gì đó, thì việc sử dụng [] .map là sai lệch. [] .forEach có ý nghĩa ngữ nghĩa và cũng chuyển ba đối số tương tự cho hàm.
gengkev

120

Trong JavaScript, không nên lặp qua một mảng có vòng lặp for-in, nhưng tốt hơn là sử dụng một forvòng lặp như:

for(var i=0, len=myArray.length; i < len; i++){}

Nó cũng được tối ưu hóa ("lưu trữ" chiều dài mảng). Nếu bạn muốn tìm hiểu thêm, hãy đọc bài viết của tôi về chủ đề này .


2
myArray.forEach (hàm (obj) {}); vẫn là tốt nhất
Jan Sverre

một cải tiến nhỏ: bạn có thể sử dụng ++ithay vìi++
roberkules

14
++ilà một tối ưu hóa trường học cũ mà các trình biên dịch hiện đại thực hiện cho bạn trong một vòng lặp for từ rất lâu rồi :) stackoverflow.com/a/1547433/1033348
ngryman

6
Bạn phải cẩn thận khi sử dụng vòng lặp này. Tôi bắt đầu sử dụng nó và gặp một lỗi khó theo dõi vì một lỗi tôi đã mắc phải. Nếu bạn lồng hai vòng như thế này: jsfiddle.net/KQwmL/1 . Bạn phải cẩn thận đặt tên var len khác nhau trong hai vòng, nếu không vòng lặp thứ hai sẽ ghi đè lên len thứ nhất.
Rui Marques

1
Rui Marques - bạn có thể đặt tên cho biến của mình i_stophoặc i_endthay vì len. Nó chỉ có thể đọc được (nếu không phải như vậy!), Và bạn sẽ tự nhiên tránh được loại vấn đề này (vì vòng lặp khác của bạn sẽ nhận được, ví dụ, j_stop).
Chip Hogg

119

cho (hãy của myStringArray) {

(Trả lời trực tiếp câu hỏi của bạn: bây giờ bạn có thể!)

Hầu hết các câu trả lời khác đều đúng, nhưng họ không đề cập (như bài viết này) rằng ECMA Script  6  2015 đang mang đến một cơ chế mới để thực hiện phép lặp, for..ofvòng lặp.

Cú pháp mới này là cách thanh lịch nhất để lặp lại một mảng trong javascript (miễn là bạn không cần chỉ số lặp).

Hiện tại nó hoạt động với Firefox 13+, Chrome 37+ và nó không hoạt động với các trình duyệt khác (xem khả năng tương thích trình duyệt bên dưới). May mắn thay, chúng tôi có các trình biên dịch JS (như Babel ) cho phép chúng tôi sử dụng các tính năng thế hệ tiếp theo ngày hôm nay.

Nó cũng hoạt động trên Node (tôi đã thử nghiệm nó trên phiên bản 0.12.0).

Lặp lại một mảng

// You could also use "let" instead of "var" for block scope.
for (var letter of ["a", "b", "c"]) { 
   console.log(letter); 
}

Lặp lại một mảng các đối tượng

var band = [
  {firstName : 'John', lastName: 'Lennon'}, 
  {firstName : 'Paul', lastName: 'McCartney'}
];

for(var member of band){
  console.log(member.firstName + ' ' + member.lastName); 
}

Lặp lại một máy phát điện:

(ví dụ được trích xuất từ https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of )

function* fibonacci() { // a generator function
  let [prev, curr] = [1, 1];
  while (true) {
    [prev, curr] = [curr, prev + curr];
    yield curr;
  }
}

for (let n of fibonacci()) {
  console.log(n);
  // truncate the sequence at 1000
  if (n >= 1000) {
    break;
  }
}

Bảng tương thích: http : // Khangax.github.io/es5-compat-table/es6/#For..of vòng lặp

Spec: http://wiki.ecmascript.org/doku.php?id=harmony:iterators

}


Nếu bạn đang sử dụng ES6, tôi sẽ đề xuất const sthay vìvar s
joeytwiddle

Trong các thử nghiệm của tôi trên các mảng lớn, việc sử dụng var s of arrgần gấp đôi (1,9 lần) thời gian thực hiện so với sử dụng một bộ đếm vòng lặp đơn giản và truy xuất các phần tử theo chỉ mục trong nodejs
theferrit32

Tại sao những thứ kỳ lạ trong dòng đầu tiên và cuối cùng?
Peter Mortensen

91

Opera, Safari, Firefox và Chrome hiện đều chia sẻ một tập hợp các phương thức Array nâng cao để tối ưu hóa nhiều vòng lặp phổ biến.

Bạn có thể không cần tất cả chúng, nhưng chúng có thể rất hữu ích, hoặc sẽ là nếu mọi trình duyệt hỗ trợ chúng.

Mozilla Labs đã xuất bản các thuật toán mà cả họ và WebKit đều sử dụng, để bạn có thể tự thêm chúng vào.

bộ lọc trả về một mảng các mục thỏa mãn một số điều kiện hoặc kiểm tra.

mọi trả về true nếu mọi thành viên mảng vượt qua bài kiểm tra.

một số trả về true nếu có vượt qua bài kiểm tra.

forEach chạy một hàm trên mỗi thành viên mảng và không trả về bất cứ thứ gì.

map giống như forEach, nhưng nó trả về một mảng kết quả của hoạt động cho từng phần tử.

Các phương thức này đều có một hàm cho đối số đầu tiên của chúng và có một đối số thứ hai tùy chọn, đó là một đối tượng có phạm vi bạn muốn áp đặt cho các thành viên mảng khi chúng lặp qua hàm.

Bỏ qua nó cho đến khi bạn cần nó.

indexOflastIndexOf tìm vị trí thích hợp của phần tử đầu tiên hoặc cuối cùng khớp chính xác với đối số của nó.

(function(){
    var p, ap= Array.prototype, p2={
        filter: function(fun, scope){
            var L= this.length, A= [], i= 0, val;
            if(typeof fun== 'function'){
                while(i< L){
                    if(i in this){
                        val= this[i];
                        if(fun.call(scope, val, i, this)){
                            A[A.length]= val;
                        }
                    }
                    ++i;
                }
            }
            return A;
        },
        every: function(fun, scope){
            var L= this.length, i= 0;
            if(typeof fun== 'function'){
                while(i<L){
                    if(i in this && !fun.call(scope, this[i], i, this))
                        return false;
                    ++i;
                }
                return true;
            }
            return null;
        },
        forEach: function(fun, scope){
            var L= this.length, i= 0;
            if(typeof fun== 'function'){
                while(i< L){
                    if(i in this){
                        fun.call(scope, this[i], i, this);
                    }
                    ++i;
                }
            }
            return this;
        },
        indexOf: function(what, i){
            i= i || 0;
            var L= this.length;
            while(i< L){
                if(this[i]=== what)
                    return i;
                ++i;
            }
            return -1;
        },
        lastIndexOf: function(what, i){
            var L= this.length;
            i= i || L-1;
            if(isNaN(i) || i>= L)
                i= L-1;
            else
                if(i< 0) i += L;
            while(i> -1){
                if(this[i]=== what)
                    return i;
                --i;
            }
            return -1;
        },
        map: function(fun, scope){
            var L= this.length, A= Array(this.length), i= 0, val;
            if(typeof fun== 'function'){
                while(i< L){
                    if(i in this){
                        A[i]= fun.call(scope, this[i], i, this);
                    }
                    ++i;
                }
                return A;
            }
        },
        some: function(fun, scope){
            var i= 0, L= this.length;
            if(typeof fun== 'function'){
                while(i<L){
                    if(i in this && fun.call(scope, this[i], i, this))
                        return true;
                    ++i;
                }
                return false;
            }
        }
    }
    for(p in p2){
        if(!ap[p])
            ap[p]= p2[p];
    }
    return true;
})();

1
Bổ sung: IE hỗ trợ forEach kể từ phiên bản 9, xem forEach Phương thức MSDN
rwitzel

75

Giới thiệu

Từ thời còn học đại học, tôi đã lập trình bằng Java, JavaScript, Pascal, ABAP , PHP, Progress 4GL, C / C ++ và có thể một vài ngôn ngữ khác mà tôi không thể nghĩ ra ngay bây giờ.

Mặc dù tất cả chúng đều có những đặc điểm ngôn ngữ riêng, mỗi ngôn ngữ này có chung nhiều khái niệm cơ bản. Các khái niệm này bao gồm các thủ tục / chức năng IF, FOR-statements, WHILE-loops và -loops.


Một for-loop truyền thống

Một forvòng lặp truyền thống có ba thành phần:

  1. Việc khởi tạo: được thực hiện trước khi khối nhìn được thực thi lần đầu tiên
  2. Điều kiện: kiểm tra một điều kiện mỗi lần trước khi khối vòng lặp được thực thi và thoát khỏi vòng lặp nếu sai
  3. Suy nghĩ lại: được thực hiện mỗi lần sau khi khối vòng lặp được thực thi

Ba thành phần này được phân tách với nhau bằng một ; biểu tượng. Nội dung cho mỗi ba thành phần này là tùy chọn, có nghĩa là sau đây là forvòng lặp tối thiểu nhất có thể:

for (;;) {
    // Do stuff
}

Tất nhiên, bạn sẽ cần bao gồm một if(condition === true) { break; } hoặc một if(condition === true) { return; }nơi nào đó bên trong đó forđể làm cho nó ngừng chạy.

Tuy nhiên, thông thường, việc khởi tạo được sử dụng để khai báo một chỉ mục, điều kiện được sử dụng để so sánh chỉ mục đó với giá trị tối thiểu hoặc tối đa và sau đó được sử dụng để tăng chỉ mục:

for (var i = 0, length = 10; i < length; i++) {
    console.log(i);
}

Sử dụng một forvòng lặp truyền thống để lặp qua một mảng

Cách truyền thống để lặp qua một mảng là:

for (var i = 0, length = myArray.length; i < length; i++) {
    console.log(myArray[i]);
}

Hoặc, nếu bạn muốn lặp lại, bạn làm điều này:

for (var i = myArray.length - 1; i > -1; i--) {
    console.log(myArray[i]);
}

Tuy nhiên, có nhiều biến thể có thể, ví dụ như biến thể này:

for (var key = 0, value = myArray[key], length = myArray.length; key < length; value = myArray[++key]) {
    console.log(value);
}

... hoặc cái này ...

var i = 0, length = myArray.length;
for (; i < length;) {
    console.log(myArray[i]);
    i++;
}

... hoặc cái này:

var key = 0, value;
for (; value = myArray[key++];){
    console.log(value);
}

Bất cứ điều gì hoạt động tốt nhất phần lớn là vấn đề của cả sở thích cá nhân và trường hợp sử dụng cụ thể mà bạn đang thực hiện.

Lưu ý rằng mỗi biến thể này đều được hỗ trợ bởi tất cả các trình duyệt, kể cả những biến thể rất cũ!


Một while vòng lặp

Một thay thế cho một forvòng lặp là một whilevòng lặp. Để lặp qua một mảng, bạn có thể làm điều này:

var key = 0;
while(value = myArray[key++]){
    console.log(value);
}

Giống như các forvòng lặp truyền thống ,while các vòng lặp được hỗ trợ bởi ngay cả các trình duyệt lâu đời nhất.

Ngoài ra, lưu ý rằng mỗi vòng lặp while có thể được viết lại dưới dạng forvòng lặp. Ví dụ: whilevòng lặp ở trên hoạt động theo cách chính xác giống như forvòng này :

for(var key = 0; value = myArray[key++];){
    console.log(value);
}

For...infor...of

Trong JavaScript, bạn cũng có thể làm điều này:

for (i in myArray) {
    console.log(myArray[i]);
}

Điều này nên được sử dụng cẩn thận, tuy nhiên, vì nó không hoạt động giống như một forvòng lặp truyền thống trong mọi trường hợp và có những tác dụng phụ tiềm ẩn cần được xem xét. Xem Tại sao sử dụng "for ... in" với việc lặp mảng là một ý tưởng tồi? để biết thêm chi tiết.

Thay thế cho for...in, bây giờ cũng cho for...of. Ví dụ sau đây cho thấy sự khác biệt giữa một for...ofvòng lặp và một for...invòng lặp:

var myArray = [3, 5, 7];
myArray.foo = "hello";

for (var i in myArray) {
  console.log(i); // logs 0, 1, 2, "foo"
}

for (var i of myArray) {
  console.log(i); // logs 3, 5, 7
}

Ngoài ra, bạn cần xem xét rằng không có phiên bản Internet Explorer nào hỗ trợ for...of( Edge 12+ ) và điều đó for...inyêu cầu ít nhất Internet Explorer 10.


Array.prototype.forEach()

Một thay thế cho for-loops là Array.prototype.forEach(), sử dụng cú pháp sau:

myArray.forEach(function(value, key, myArray) {
    console.log(value);
});

Array.prototype.forEach() được hỗ trợ bởi tất cả các trình duyệt hiện đại, cũng như Internet Explorer 9 trở lên.


Thư viện

Cuối cùng, nhiều thư viện tiện ích cũng có foreachbiến thể riêng . AFAIK, ba cái phổ biến nhất là:

jQuery.each(), trong jQuery :

$.each(myArray, function(key, value) {
    console.log(value);
});

_.each(), trong Underscore.js :

_.each(myArray, function(value, key, myArray) {
    console.log(value);
});

_.forEach(), trong Lodash.js :

_.forEach(myArray, function(value, key) {
    console.log(value);
});

68

Sử dụng vòng lặp while ...

var i=0, item, items = ['one','two','three'];
while(item = items[i++]){
    console.log(item);
}

nhật ký: 'một', 'hai', 'ba'

Và theo thứ tự ngược lại, một vòng lặp thậm chí hiệu quả hơn

var items = ['one','two','three'], i = items.length;
while(i--){
    console.log(items[i]);
}

nhật ký: 'ba', 'hai', 'một'

Hoặc forvòng lặp cổ điển

var items = ['one','two','three']
for(var i=0, l = items.length; i < l; i++){
    console.log(items[i]);
}

nhật ký: 'một', 'hai', 'ba'

Tham khảo: http://www.sitepoint.com/google-clenses-how-not-to-write-javascript/


21
Ví dụ đầu tiên về cú pháp "while" sẽ không hoạt động nếu bất kỳ phần tử mảng nào là sai.
Chris Cooper

2
... và vòng lặp while này tương đương với: for (var i = 0, item; item = items [i]; i ++), sẽ loại bỏ sự cần thiết phải khai báo các biến chỉ mục và biến mục trước ...
Stijn de Witt


39

Nếu bạn muốn một cách ngắn gọn để viết một vòng lặp nhanh bạn có thể lặp lại theo chiều ngược lại:

for (var i=myArray.length;i--;){
  var item=myArray[i];
}

Điều này có lợi ích của bộ nhớ đệm độ dài (tương tự for (var i=0, len=myArray.length; i<len; ++i)và không giống nhau for (var i=0; i<myArray.length; ++i)) trong khi có ít ký tự để nhập.

Thậm chí có một số lần bạn phải lặp lại theo chiều ngược lại, chẳng hạn như khi lặp qua một NodeList trực tiếp nơi bạn dự định xóa các mục khỏi DOM trong quá trình lặp.


16
Đối với những người không có được những gì thật tài tình: Biểu thức i-- được đánh giá đầu tiên và cho phép vòng lặp tiếp tục khi nó không sai lệch ... Sau đó, bộ đếm bị giảm. Ngay khi tôi trở thành số 0, nó sẽ thoát ra khỏi vòng lặp vì số 0 là giá trị giả trong Javascript.
Stijn de Witt

5
giả dối? Bạn có nghĩa là chim ưng. Tất cả chúng ta hãy sử dụng thuật ngữ thích hợp để tránh nhầm lẫn;)
danwellman

4
Tôi đã thấy thuật ngữ giả được sử dụng bởi những người mà tôi coi là những bậc thầy. Nếu nó đủ tốt cho họ thì nó đủ tốt cho tôi. Cũng có một sự thất vọng khi thấy rằng bình luận của tôi thực sự không có ý nghĩa và thêm lời giải thích / cái nhìn sâu sắc nhận được 0 upvote, nhưng nhận xét rằng nitpicks về một thuật ngữ trong bình luận của tôi nhận được 4. Tôi cũng chỉ là vấn đề ưu tiên.
Stijn de Witt

"Bộ nhớ đệm chiều dài"? Độ dài được lưu trữ dưới dạng một số nguyên trong mảng, nó không được đo mỗi khi bạn truy cập nó. Ở đây không có lợi ích trong việc sao chép giá trị độ dài vào một biến khác.
Linh tinh

1
@Mousiverse Những ngày này chắc chắn không có; trong những năm qua, việc lặp lại các mảng JavaScript lưu trữ độ dài ở phía JavaScript (thay vì đạt được trong quá trình thực hiện) là một mức tăng hoàn hảo rõ ràng (khi vi mô hóa). Ví dụ, for (var i=0,len=array.length;i<len;++i)là một vòng lặp phổ biến, hợp lý để viết.
Phrogz

36

Một số trường hợp sử dụng lặp qua một mảng theo cách lập trình chức năng trong JavaScript:

1. Chỉ cần lặp qua một mảng

const myArray = [{x:100}, {x:200}, {x:300}];

myArray.forEach((element, index, array) => {
    console.log(element.x); // 100, 200, 300
    console.log(index); // 0, 1, 2
    console.log(array); // same myArray object 3 times
});

Lưu ý: Array.prototype.forEach () không phải là một cách chức năng nói đúng, vì hàm này làm tham số đầu vào không được phép trả về một giá trị, do đó không thể được coi là một hàm thuần túy.

2. Kiểm tra xem có bất kỳ phần tử nào trong một mảng vượt qua kiểm tra không

const people = [
    {name: 'John', age: 23}, 
    {name: 'Andrew', age: 3}, 
    {name: 'Peter', age: 8}, 
    {name: 'Hanna', age: 14}, 
    {name: 'Adam', age: 37}];

const anyAdult = people.some(person => person.age >= 18);
console.log(anyAdult); // true

3. Chuyển đổi sang một mảng mới

const myArray = [{x:100}, {x:200}, {x:300}];

const newArray= myArray.map(element => element.x);
console.log(newArray); // [100, 200, 300]

Lưu ý: Phương thức map () tạo ra một mảng mới với kết quả gọi một hàm được cung cấp trên mọi phần tử trong mảng gọi.

4. Tính tổng một tài sản cụ thể và tính trung bình của nó

const myArray = [{x:100}, {x:200}, {x:300}];

const sum = myArray.map(element => element.x).reduce((a, b) => a + b, 0);
console.log(sum); // 600 = 0 + 100 + 200 + 300

const average = sum / myArray.length;
console.log(average); // 200

5. Tạo một mảng mới dựa trên bản gốc nhưng không sửa đổi nó

const myArray = [{x:100}, {x:200}, {x:300}];

const newArray= myArray.map(element => {
    return {
        ...element,
        x: element.x * 2
    };
});

console.log(myArray); // [100, 200, 300]
console.log(newArray); // [200, 400, 600]

6. Đếm số lượng của từng loại

const people = [
    {name: 'John', group: 'A'}, 
    {name: 'Andrew', group: 'C'}, 
    {name: 'Peter', group: 'A'}, 
    {name: 'James', group: 'B'}, 
    {name: 'Hanna', group: 'A'}, 
    {name: 'Adam', group: 'B'}];

const groupInfo = people.reduce((groups, person) => {
    const {A = 0, B = 0, C = 0} = groups;
    if (person.group === 'A') {
        return {...groups, A: A + 1};
    } else if (person.group === 'B') {
        return {...groups, B: B + 1};
    } else {
        return {...groups, C: C + 1};
    }
}, {});

console.log(groupInfo); // {A: 3, C: 1, B: 2}

7. Lấy một tập hợp con của một mảng dựa trên các tiêu chí cụ thể

const myArray = [{x:100}, {x:200}, {x:300}];

const newArray = myArray.filter(element => element.x > 250);
console.log(newArray); // [{x:300}] 

Lưu ý: Phương thức filter () tạo ra một mảng mới với tất cả các phần tử vượt qua kiểm tra được thực hiện bởi hàm được cung cấp.

8. Sắp xếp một mảng

const people = [
  { name: "John", age: 21 },
  { name: "Peter", age: 31 },
  { name: "Andrew", age: 29 },
  { name: "Thomas", age: 25 }
];

let sortByAge = people.sort(function (p1, p2) {
  return p1.age - p2.age;
});

console.log(sortByAge);

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

9. Tìm một phần tử trong một mảng

const people = [ {name: "john", age:23},
                {name: "john", age:43},
                {name: "jim", age:101},
                {name: "bob", age:67} ];

const john = people.find(person => person.name === 'john');
console.log(john);

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

Phương thức Array.prototype.find () trả về giá trị của phần tử đầu tiên trong mảng thỏa mãn hàm kiểm tra được cung cấp.

Người giới thiệu


30

Có một cách để làm điều đó khi bạn có rất ít phạm vi ẩn trong vòng lặp của mình và loại bỏ các biến phụ.

var i = 0,
     item;

// note this is weak to sparse arrays or falsey values
for ( ; item = myStringArray[i++] ; ){ 
    item; // This is the string at the index.
}

Hoặc nếu bạn thực sự muốn lấy id và có một forvòng lặp thực sự cổ điển :

var i = 0,
    len = myStringArray.length; // cache the length

for ( ; i < len ; i++ ){
    myStringArray[i]; // Don't use this if you plan on changing the length of the array
}

Trình duyệt hiện tại tất cả các phương pháp hỗ trợ iterator forEach, map, reduce, filtervà một loạt các phương pháp khác trên nguyên mẫu mảng .


3
Lưu ý rằng một số trình thông dịch (ví dụ V8) sẽ tự động lưu trữ độ dài của mảng nếu mã được gọi đủ số lần và nó phát hiện ra rằng độ dài không được sửa đổi bởi vòng lặp.
Phrogz

Cảm ơn thông tin @Phrogz đúng là có rất nhiều tối ưu hóa mà VM có thể thực hiện, nhưng vì các trình duyệt cũ hơn không có điều này nên vẫn là cách tốt nhất để tối ưu hóa cho nó vì nó quá rẻ.
Gabriel

1
@Gabriel: Tại sao? Vui lòng đưa ra các ví dụ trong thế giới thực cho thấy rằng không lưu bộ nhớ cache độ dài thực sự là một nút cổ chai hiệu năng. Tôi theo phương pháp 'tối ưu hóa sớm là gốc rễ của mọi phương pháp'. Tôi sẽ khắc phục một vòng lặp thực sự gây ra sự cố khi tôi gặp phải nó ...
Stijn de Witt

1
@StijndeWitt imo nó chỉ là một vấn đề phong cách. Thành thật mà nói tôi thậm chí không còn sử dụng cho các vòng lặp thay vào đó dựa vào gạch dưới cho những thứ như _.each, _.map, v.v. để làm những việc này. Khi tôi đã viết các vòng lặp như thế này, tôi đã lưu trữ chiều dài chủ yếu để tất cả các khai báo biến của tôi nằm ở một nơi, ở đầu hàm của tôi. Theo lời khuyên của tôi về vấn đề này là không quan trọng đối với bất kỳ ứng dụng trong thế giới thực. Tối ưu hóa sớm là rất tệ, nhưng nếu tối ưu hóa xảy ra do các quyết định phong cách, tôi không nghĩ nó thực sự quan trọng.
Gabriel

1
@Gabriel Tôi tin rằng JavaScript đã hỗ trợ chức năng bản đồ trên các mảng, không cần phải giới thiệu thêm một lib cho điều đó.
Noz

28

Có nhiều cách khác nhau để lặp qua mảng trong JavaScript.

Vòng lặp chung:

var i;
for (i = 0; i < substr.length; ++i) {
    // Do something with `substr[i]`
}

ES5 của forEach:

substr.forEach(function(item) {
    // Do something with `item`
});

jQuery.each:

jQuery.each(substr, function(index, item) {
    // Do something with `item` (or `this` is also `item` if you like)
});

Có một cái nhìn này để biết thông tin chi tiết hoặc bạn cũng có thể kiểm tra MDN cho vòng lặp thông qua một mảng trong JavaScript & sử dụng jQuery kiểm tra jQuery cho mỗi .


27

Tôi hoàn toàn khuyên bạn nên sử dụng thư viện underscore.js . Nó cung cấp cho bạn các hàm khác nhau mà bạn có thể sử dụng để lặp qua các mảng / bộ sưu tập.

Ví dụ:

_.each([1, 2, 3], function(num){ alert(num); });
=> alerts each number in turn...

7
Đối với những người mới khám phá câu hỏi này, tôi chỉ muốn chỉ ra Lo-Dash , một người kế thừa tinh thần của Underscore cải thiện nó theo nhiều cách.
Mark Reed

3
Tại sao sử dụng underscorenếu ECMA-262 đã được thêm forEachẩn dụ. Mã riêng luôn tốt hơn.
Walter Chapilliquen - wZVanG

27

Vòng lặp mảng:

for(var i = 0; i < things.length; i++){
    var thing = things[i];
    console.log(thing);
}

Vòng lặp đối tượng:

for(var prop in obj){
    var propValue = obj[prop];
    console.log(propValue);
}

27

, bạn có thể làm tương tự trong JavaScript bằng cách sử dụng một vòng lặp, nhưng không giới hạn ở đó, có nhiều cách để thực hiện một vòng lặp trên các mảng trong JavaScript. Hãy tưởng tượng bạn có mảng này bên dưới và bạn muốn thực hiện một vòng lặp trên nó:

var arr = [1, 2, 3, 4, 5];

Đây là những giải pháp:

1) Đối với vòng lặp

Một forvòng lặp là một cách phổ biến lặp qua mảng trong JavaScript, nhưng không coi là giải pháp nhanh nhất cho mảng lớn:

for (var i=0, l=arr.length; i<l; i++) {
  console.log(arr[i]);
}

2) Vòng lặp while

Vòng lặp while được coi là cách nhanh nhất để lặp qua các mảng dài, nhưng nó thường ít được sử dụng trong mã JavaScript:

let i=0;

while (arr.length>i) {
    console.log(arr[i]);
    i++;
}

3) Làm trong khi
A do whileđang làm điều tương tự như whilevới một số khác biệt cú pháp như dưới đây:

let i=0;
do {
  console.log(arr[i]);
  i++;
}
while (arr.length>i);

Đây là những cách chính để thực hiện các vòng lặp JavaScript, nhưng có một vài cách khác để làm điều đó.

Ngoài ra, chúng tôi sử dụng một for invòng lặp để lặp qua các đối tượng trong JavaScript.

Ngoài ra nhìn vào map(), filter(), reduce(), vv chức năng trên một mảng trong JavaScript. Họ có thể làm mọi thứ nhanh hơn và tốt hơn so với việc sử dụng whilefor.

Đây là một bài viết tốt nếu bạn muốn tìm hiểu thêm về các hàm không đồng bộ qua các mảng trong JavaScript.

Lập trình chức năng đã và đang làm cho khá nổi trong thế giới phát triển ngày nay. Và vì lý do chính đáng: Các kỹ thuật chức năng có thể giúp bạn viết nhiều mã khai báo dễ hiểu hơn trong nháy mắt, cấu trúc lại và kiểm tra.

Một trong những nền tảng của lập trình chức năng là việc sử dụng đặc biệt các danh sách và hoạt động danh sách. Và những thứ đó chính xác là những gì âm thanh giống như chúng: mảng của sự vật, và những thứ bạn làm với chúng. Nhưng lối tư duy chức năng đối xử với họ hơi khác so với bạn tưởng.

Bài viết này sẽ xem xét kỹ những gì tôi muốn gọi là các hoạt động danh sách "ba lớn": bản đồ, bộ lọc và rút gọn. Quấn đầu quanh ba chức năng này là một bước quan trọng để có thể viết mã chức năng sạch và mở ra cánh cửa cho các kỹ thuật mạnh mẽ của lập trình chức năng và phản ứng.

Điều đó cũng có nghĩa là bạn sẽ không bao giờ phải viết một vòng lặp nữa.

Đọc thêm >> tại đây :


Có thực sự có một sự khác biệt hiệu suất trước một vòng lặp for và một vòng lặp while khi lặp qua một mảng không? Tôi đã có ấn tượng rằng sự khác biệt chủ yếu là cú pháp
shea

24

Nếu bất kỳ ai quan tâm đến khía cạnh hiệu năng của nhiều cơ chế có sẵn cho các lần lặp Array, tôi đã chuẩn bị các bài kiểm tra JSPerf sau:

https://jsperf.com/fastest-array-iterator

Kết quả thực hiện

Các kết quả:

Trình for()lặp truyền thống , cho đến nay là phương pháp nhanh nhất, đặc biệt là khi được sử dụng với độ dài mảng được lưu trữ .

let arr = [1,2,3,4,5];

for(let i=0, size=arr.length; i<size; i++){
    // Do something
}

Các Array.prototype.forEach()và các Array.prototype.map()phương pháp là xấp xỉ chậm nhất, có lẽ là hậu quả của các overhead chức năng cuộc gọi .


sử dụng tốt hơn i = i +1thay vìi++
DarckBlezzer

2
Có thể được cải thiện: Vui lòng sử dụng: ++ i thay vì i ++, điều này sẽ tránh một đối tượng tạm thời. Vì vậy, nó làm giảm việc sử dụng bộ nhớ và thời gian cpu (không cần phân bổ)!
PowerStat

@PowerStat bạn có thể cung cấp một liên kết hoặc tài liệu tham khảo về điều đó? Tôi chưa bao giờ nghĩ về nó, nghe có vẻ thú vị ...
colxi

1
@colxi Đối với những điều thú vị như vậy, bạn nên đọc những thứ C ++ khó tính từ Herb Sutter và Scott Meyers. Điều ++ i vs i ++ có trong cuốn sách: C ++ đặc biệt: 47 Câu đố kỹ thuật, vấn đề lập trình và giải pháp - Tôi cũng có thể tìm thấy nó trên gotw.ca nhưng có thể được chứng minh cho mọi ngôn ngữ lập trình.
PowerStat

21

Nếu bạn đang sử dụng thư viện jQuery, hãy cân nhắc sử dụng http://api.jquery.com/jQuery.each/

Từ tài liệu:

jQuery.each( collection, callback(indexInArray, valueOfElement) )

Trả về: Đối tượng

Mô tả: Hàm lặp chung, có thể được sử dụng để lặp lại liên tục trên cả đối tượng và mảng. Mảng và các đối tượng giống như mảng có thuộc tính độ dài (chẳng hạn như đối tượng đối số của hàm) được lặp theo chỉ số số, từ 0 đến chiều dài-1. Các đối tượng khác được lặp qua các thuộc tính được đặt tên của chúng.

Các $.each()chức năng không giống như $(selector).each(), được sử dụng để lặp, độc quyền, trên một đối tượng jQuery. Các $.each() chức năng có thể được sử dụng để lặp qua bất kỳ bộ sưu tập, cho dù đó là một bản đồ (đối tượng JavaScript) hoặc một mảng. Trong trường hợp của một mảng, cuộc gọi lại được thông qua một chỉ mục mảng và giá trị mảng tương ứng mỗi lần. (Giá trị cũng có thể được truy cập thông qua thistừ khóa, nhưng Javascript sẽ luôn bao bọc thisgiá trị dưới dạng Objectngay cả khi đó là một chuỗi đơn giản hoặc giá trị số.) Phương thức trả về đối số đầu tiên của nó, đối tượng được lặp lại.


9
jQuery cho tất cả mọi thứ?
Ngoại lệ

6
Đồng ý với Ngoại lệ. Đừng đánh giá thấp tác động của sự phụ thuộc thêm. Tôi sẽ khuyên bạn điều này ngoại trừ trong mã đã sử dụng jQuery rất nhiều.
Stijn de Witt

2
Cập nhật: Những ngày này, bạn có thể sử dụng Array.forEach để có được nhiều hiệu ứng tương tự với các mảng gốc.
Stijn de Witt

21

Tôi chưa thấy biến thể này, mà cá nhân tôi thích nhất:

Cho một mảng:

var someArray = ["some", "example", "array"];

Bạn có thể lặp qua nó mà không bao giờ truy cập vào thuộc tính độ dài:

for (var i=0, item; item=someArray[i]; i++) {
  // item is "some", then "example", then "array"
  // i is the index of item in the array
  alert("someArray[" + i + "]: " + item);
}

Xem JsFiddle này chứng minh rằng: http://jsfiddle.net/prvzk/

Điều này chỉ hoạt động cho các mảng không thưa thớt. Có nghĩa là thực sự có một giá trị tại mỗi chỉ mục trong mảng. Tuy nhiên, tôi thấy rằng trong thực tế, tôi hầu như không bao giờ sử dụng các mảng thưa thớt trong JavaScript ... Trong những trường hợp như vậy, việc sử dụng một đối tượng làm bản đồ / hashtable thường dễ dàng hơn rất nhiều. Nếu bạn có một mảng thưa thớt và muốn lặp trên 0 .. length-1, bạn cần cấu trúc for (var i = 0; i <someArray.length; ++ i), nhưng bạn vẫn cần một ifvòng lặp bên trong để kiểm tra xem phần tử tại chỉ mục hiện tại có thực sự được xác định hay không.

Ngoài ra, như CMS đề cập trong một bình luận bên dưới, bạn chỉ có thể sử dụng điều này trên các mảng không chứa bất kỳ giá trị giả nào. Mảng các chuỗi từ ví dụ hoạt động, nhưng nếu bạn có các chuỗi trống hoặc các số bằng 0 hoặc NaN, v.v. thì vòng lặp sẽ bị đứt sớm. Một lần nữa trong thực tế, điều này hầu như không phải là vấn đề đối với tôi, nhưng đó là điều cần lưu ý, điều này khiến cho việc này phải suy nghĩ trước khi bạn sử dụng nó ... Điều đó có thể làm mất quyền đối với một số người :)

Những gì tôi thích về vòng lặp này là:

  • Viết ngắn gọn
  • Không cần truy cập (huống chi bộ đệm) thuộc tính độ dài
  • Mục để truy cập được tự động xác định trong thân vòng lặp dưới tên bạn chọn.
  • Kết hợp rất tự nhiên với Array.push và Array.splice để sử dụng các mảng như danh sách / ngăn xếp

Lý do điều này hoạt động là do đặc tả mảng bắt buộc rằng khi bạn đọc một mục từ chỉ mục> = độ dài của mảng, nó sẽ trả về không xác định. Khi bạn viết vào một vị trí như vậy, nó sẽ thực sự cập nhật độ dài.

Đối với tôi, cấu trúc này mô phỏng gần nhất cú pháp Java 5 mà tôi yêu thích:

for (String item : someArray) {
}

... với lợi ích bổ sung là cũng biết về chỉ số hiện tại bên trong vòng lặp


14
Chú ý rằng với cách tiếp cận này, vòng lặp sẽ dừng lại càng sớm mà nó tìm thấy một giá trị falsey , chẳng hạn như một chuỗi rỗng, 0, false, NaN, nullhoặc undefined, thậm chí trước khi iđạt chiều dài, ví dụ như: jsfiddle.net/prvzk/1
CMS

3
Các điều kiện vòng lặp có thể được (item=someArray[i]) !== undefined.
daniel1426

18

Có một phương pháp để chỉ lặp lại các thuộc tính của đối tượng, không bao gồm các thuộc tính của nguyên mẫu:

for (var i in array) if (array.hasOwnProperty(i)) {
    // Do something with array[i]
}

nhưng nó vẫn sẽ lặp đi lặp lại trên các thuộc tính được xác định tùy chỉnh.

Trong JavaScript, bất kỳ thuộc tính tùy chỉnh nào cũng có thể được gán cho bất kỳ đối tượng nào, bao gồm cả một mảng.

Nếu ai muốn lặp mảng trên sparsed, for (var i = 0; i < array.length; i++) if (i in array)hoặc array.forEachvới es5shimnên được sử dụng.


Và sử dụng như thế nào for (var i in array) if (++i)?
Daniel Sokolowski

15

Có một vài cách để làm điều đó trong JavaScript. Hai ví dụ đầu tiên là các mẫu JavaScript. Cái thứ ba sử dụng một thư viện JavaScript, nghĩa là jQuery sử dụng .each()hàm này.

var myStringArray = ["hello", "World"];
for(var i in myStringArray) {
  alert(myStringArray[i]);
}

var myStringArray = ["hello", "World"];
for (var i=0; i < myStringArray.length; i++) {
  alert(myStringArray[i]);
}

var myStringArray = ["hello", "World"];
$.each(myStringArray, function(index, value){
  alert(value);
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>


for...innên tránh cho các đối tượng giống như Array
brk 5/12/2016

15

Cách thanh lịch và nhanh nhất

var arr = [1, 2, 3, 1023, 1024];
for (var value; value = arr.pop();) {
    value + 1
}

http://jsperf.com/native-loop-performance/8


Đã chỉnh sửa (vì tôi đã sai)


So sánh các phương pháp để lặp qua một mảng gồm 100000 mục và thực hiện một thao tác tối thiểu với giá trị mới mỗi lần.

Sự chuẩn bị:

<script src="//code.jquery.com/jquery-2.1.0.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js"></script>
<script>
    Benchmark.prototype.setup = function() {
        // Fake function with minimal action on the value
        var tmp = 0;
        var process = function(value) {
            tmp = value; // Hold a reference to the variable (prevent engine optimisation?)
        };

        // Declare the test Array
        var arr = [];
        for (var i = 0; i < 100000; i++)
            arr[i] = i;
    };
</script>

Các xét nghiệm:

<a href="http://jsperf.com/native-loop-performance/16" 
   title="http://jsperf.com/native-loop-performance/16"
><img src="http://i.imgur.com/YTrO68E.png" title="Hosted by imgur.com" /></a>

Vòng lặp này dường như không tuân theo thứ tự của các mục trong mảng.
Deniz Ozger

Bài kiểm tra của tôi đã sai. Đó là chính xác, hiển thị tất cả các BẢNG bây giờ. jsperf.com/native-loop-performance/16
molokoloco

@bergi nói đúng. Vòng lặp này xóa sạch mảng khi nó lặp qua nó. Không phải những gì bạn muốn trong hầu hết các trường hợp.
Stijn de Witt

4
phá vỡ các mặt hàng falsey.
njzk2

12

Cách tiếp cận tối ưu hóa là lưu trữ độ dài của mảng và sử dụng mẫu var duy nhất khởi tạo tất cả các biến với từ khóa var duy nhất.

var i, max, myStringArray = ["Hello","World"];
for (i = 0, max = myStringArray.length; i < max; i++) {
    alert(myStringArray[i]);
   //Do something
}

Nếu thứ tự lặp không quan trọng hơn bạn nên thử vòng lặp đảo ngược, thì nhanh nhất vì nó giảm kiểm tra điều kiện trên không và giảm dần trong một câu lệnh:

var i,myStringArray = ["item1","item2"];
for (i =  myStringArray.length; i--) {
    alert(myStringArray[i]);
}

hoặc tốt hơn và sạch hơn để sử dụng vòng lặp while:

var myStringArray = ["item1","item2"],i = myStringArray.length;
while(i--) {
   // do something with fruits[i]
}

12

Trong JavaScript, có rất nhiều giải pháp để lặp một mảng.

Mã dưới đây là những mã phổ biến

/** Declare inputs */
const items = ['Hello', 'World']

/** Solution 1. Simple for */
console.log('solution 1. simple for')

for (let i = 0; i < items.length; i++) {
  console.log(items[i])
}

console.log()
console.log()

/** Solution 2. Simple while */
console.log('solution 2. simple while')

let i = 0
while (i < items.length) {
  console.log(items[i++])
}

console.log()
console.log()

/** Solution 3. forEach*/
console.log('solution 3. forEach')

items.forEach(item => {
  console.log(item)
})

console.log()
console.log()

/** Solution 4. for-of*/
console.log('solution 4. for-of')

for (const item of items) {
  console.log(item)
}

console.log()
console.log()


12

Nếu bạn muốn sử dụng jQuery, nó có một ví dụ hay trong tài liệu của nó:

 $.each([ 52, 97 ], function( index, value ) {
      alert( index + ": " + value );
 });

12

Theo tôi, cách tốt nhất là sử dụng hàm Array.forEach. Nếu bạn không thể sử dụng mà tôi sẽ đề nghị lấy polyfill từ MDN. Để làm cho nó có sẵn, nó chắc chắn là cách an toàn nhất để lặp lại qua một mảng trong JavaScript.

Array.prototype.forEach ()

Vì vậy, như những người khác đã đề xuất, đây hầu như luôn là những gì bạn muốn:

var numbers = [1,11,22,33,44,55,66,77,88,99,111];
var sum = 0;
numbers.forEach(function(n){
  sum += n;
});

Điều này đảm bảo rằng bất cứ điều gì bạn cần trong phạm vi xử lý mảng đều nằm trong phạm vi đó và bạn chỉ xử lý các giá trị của mảng, chứ không phải các thuộc tính đối tượng và các thành viên khác, đó là những gì for ..đang làm.

Sử dụng kiểu chữ C thông thường for vòng lặp hoạt động trong hầu hết các trường hợp. Điều quan trọng cần nhớ là mọi thứ trong vòng lặp đều chia sẻ phạm vi của nó với phần còn lại của chương trình của bạn, {} không tạo ra một phạm vi mới.

Vì thế:

var sum = 0;
var numbers = [1,11,22,33,44,55,66,77,88,99,111];

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

alert(i);

sẽ xuất "11" - có thể hoặc không thể là những gì bạn muốn.

Một ví dụ jsFiddle đang hoạt động: https://jsfiddle.net/ WorkClassHacker/pxpv2dh5/7 /


10

Nó không giống nhau 100%, nhưng tương tự nhau:

   var myStringArray = ['Hello', 'World']; // array uses [] not {}
    for (var i in myStringArray) {
        console.log(i + ' -> ' + myStringArray[i]); // i is the index/key, not the item
    }


1
Có vẻ như điều này sẽ gặp phải các vấn đề tương tự như các vấn đề khác trong việc sử dụng với một đối tượng mảng, trong đó các biến thành viên nguyên mẫu cũng sẽ bị bắt bởi.
Kzqai

9

Ví dụ: tôi đã sử dụng trong bảng điều khiển Firefox:

[].forEach.call(document.getElementsByTagName('pre'), function(e){ 
   console.log(e);
})

9
var x = [4, 5, 6];
for (i = 0, j = x[i]; i < x.length; j = x[++i]) {
    console.log(i,j);
}

Sạch hơn rất nhiều ...


Điều đó không sạch lắm so với z.forEach(j => console.log(j));.
Sapphire_Brick

9

Câu trả lời ngắn gọn: có. Bạn có thể làm với điều này:

var myArray = ["element1", "element2", "element3", "element4"];

for (i = 0; i < myArray.length; i++) {
  console.log(myArray[i]);
}

Trong bảng điều khiển trình duyệt, bạn có thể thấy một cái gì đó như "Element1", "Element2", v.v., được in.


9

Bạn có thể sử dụng Array.prototype.forEach(...):

var arr = ["apple", "banana", "cherry", "mango"];
arr.forEach((item, index)=>{
   //Some code...
});

Hoặc Array.prototype.map(...):

var arr = ["apple", "banana", "cherry", "mango"];
arr.map((item, index)=>{
   //Some code...
});

Hoặc jquery hoặc cho các cách lặp được đề cập trước đây.

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.