Sự khác biệt giữa các câu lệnh (cho bản in trong) và (cho bản của) trong JavaScript là gì?


410

Tôi biết for... invòng lặp là gì (nó lặp qua khóa), nhưng lần đầu tiên nghe về for... of(nó lặp lại theo giá trị).

Tôi bối rối với for... ofvòng lặp. Tôi đã không nhận được tính từ. Đây là mã dưới đây:

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

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

for (var i of arr) {
  console.log(i); // logs "3", "5", "7"
  // it is does not log "3", "5", "7", "hello"
}

Những gì tôi nhận được là, for... oflặp đi lặp lại trên các giá trị tài sản. Vậy thì tại sao nó không đăng nhập (trở lại) "3", "5", "7", "hello"thay vì "3", "5", "7"? nhưng for... invòng lặp lặp trên mỗi khóa ( "0", "1", "2", "foo"). Ở đây for... invòng lặp cũng lặp lại trên foophím. Nhưng for... ofkhông lặp lại giá trị footài sản tức là "hello". Tại sao nó lại như vậy?

Tóm lại:

Ở đây tôi điều khiển for... ofvòng lặp. Nó nên đăng nhập "3", "5", "7","hello"nhưng ở đây nó đăng nhập "3", "5", "7". Tại sao ?

Liên kết ví dụ


1
trong trường hợp bạn bỏ lỡ nó, đây là liên kết nhà phát
Anthony Russell

1
Theo như sự hiểu biết của tôi, for ... ofđã được đưa vào ngôn ngữ để khắc phục các vấn đề khi sử dụng for ... invới Mảng. Array.prototypecó thể được sửa đổi theo cách có sẵn các thuộc tính bổ sung, khiến cho việc lặp lại chúng không an toàn vì bạn có thể nhận được các khóa số mà bạn không mong đợi.
Phylogenesis

2
Đối với những người đọc trong tương lai: đây có lẽ không phải là một bản sao của Từ khóa JavaScript of(đối với các vòng lặp) , vì nó hỏi về một hành vi cụ thể của tính năng, thay vì yêu cầu tổng quan chung.
apsillers

2
Chỉ cần làm quen với việc nói " for <key> in" và " for <value> of" và nhận ra IE không hỗ trợfor..of
BotNet

Câu trả lời:


304

for in vòng lặp trên vô số tên tài sản của một đối tượng.

for of(mới trong ES6) không sử dụng một trình vòng lặp dành riêng cho đối tượng và các vòng lặp trên các giá trị được tạo bởi điều đó.

Trong ví dụ của bạn, trình lặp mảng thực hiện tất cả các giá trị trong mảng (bỏ qua các thuộc tính không chỉ mục).


9
for ... ofđược chuẩn hóa trong ES6.
Justin

2
Điều đó thật lạ, tôi thề tôi đã đọc ở đâu đó nó đã được chuyển về ES7, nhưng dường như điều đó không đúng. Lỗi của tôi.
Alexander O'Mara

40
Một ghi nhớ: 'o'f -> không phải' o'bjects, 'i'n -> không' i'terables
Placoplatr

4
một kiểu ghi nhớ khác: for... of:: mảng :: mảng luôn có độ dài, vì vậy bạn có thể nghĩ for.. [phần tử thứ n] of.. [phần tử q]
Nathan Smith

14
Một mnemonic khác ... for..in..keys=== khóa ngoại === sử dụng for...incho khóa! Như vậy, sử dụng for...ofcho các giá trị.
Gunther

237

Tôi tìm thấy câu trả lời đầy đủ tại: https://www.typescriptlang.org/docs/handbook/iterators-and-generators.html (Mặc dù nó dành cho loại script, điều này cũng tương tự với javascript)

Cả hai for..ofvà các for..incâu lệnh lặp đi lặp lại qua danh sách; mặc dù các giá trị được lặp lại khác nhau, for..intrả về một danh sách các khóa trên đối tượng được lặp lại, trong khi for..oftrả về một danh sách các giá trị của các thuộc tính số của đối tượng được lặp lại.

Dưới đây là một ví dụ minh chứng cho sự khác biệt này:

let list = [4, 5, 6];

for (let i in list) {
   console.log(i); // "0", "1", "2",
}

for (let i of list) {
   console.log(i); // "4", "5", "6"
}

Một điểm khác biệt là for..in hoạt động trên mọi đối tượng; nó phục vụ như một cách để kiểm tra các thuộc tính trên đối tượng này. for..ofmặt khác, chủ yếu quan tâm đến các giá trị của các đối tượng lặp lại. Các đối tượng tích hợp như Map và Set implement Symbol.iteratorproperty cho phép truy cập vào các giá trị được lưu trữ.

let pets = new Set(["Cat", "Dog", "Hamster"]);
pets["species"] = "mammals";

for (let pet in pets) {
   console.log(pet); // "species"
}

for (let pet of pets) {
    console.log(pet); // "Cat", "Dog", "Hamster"
}

1
Futhermore, gọi một cái gì đó như for (let i of {}) {console.log (i); } sẽ ném TypeError: VM391: 1 Uncaught TypeError: {} không thể lặp lại tại <nặc danh>: 1: 14, ít nhất là trong Chrome
kboom

TS cho chiến thắng - ví dụ không chính xác, sau này sẽ trả lại "động vật có vú", chứ không phải // "Mèo", "Chó", "Hamster"
martinp999

8
Tôi nhớ nó bằng cách: cho "trong" cho index. Và sau đó, "của" sẽ là valuescủa mỗi chỉ mục / khóa / mục.
SherylHohman

Thật tuyệt, đây sẽ là vua đối với tôi: sử dụng for-in để lặp lại các mục tôi thường phải tạo một let thisItem = items[all];biến, for...ofgiúp tắt phím đó!
Hội trường Vasily

Tôi nhớ nó bằng cách: for...innhư Object.keys(), đoán những gì? Mảng là đối tượng, sot cũng sẽ trả lại phân của họ. :)
Sujeet Agrahari

38

Cho ... trong vòng lặp

Các for ... in loop cải thiện khi những điểm yếu của các vòng lặp for bằng cách loại bỏ logic đếm và điều kiện thoát.

Thí dụ:

const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

for (const index in digits) {
  console.log(digits[index]);
}

Nhưng, bạn vẫn phải giải quyết vấn đề sử dụng một chỉ mục để truy cập các giá trị của mảng và điều đó rất hôi thối; nó gần như làm cho nó khó hiểu hơn trước.

Ngoài ra, vòng lặp for ... in có thể khiến bạn gặp rắc rối lớn khi bạn cần thêm một phương thức bổ sung vào một mảng (hoặc một đối tượng khác). Bởi vì ... trong vòng lặp trên tất cả các thuộc tính có thể đếm được, điều này có nghĩa là nếu bạn thêm bất kỳ thuộc tính bổ sung nào vào nguyên mẫu của mảng, thì các thuộc tính đó cũng sẽ xuất hiện trong vòng lặp.

Array.prototype.decimalfy = function() {
  for (let i = 0; i < this.length; i++) {
    this[i] = this[i].toFixed(2);
  }
};

const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

for (const index in digits) {
  console.log(digits[index]);
}

Bản in:

0

1

2

3

4

5

6

7

số 8

9

hàm () {for (let i = 0; i <this.length; i ++) {this [i] = this [i] .toFixed (2); }}

Đây là lý do tại sao ... trong các vòng lặp không được khuyến khích khi lặp trên các mảng.

LƯU Ý : Vòng lặp forEach là một loại vòng lặp for khác trong JavaScript. Tuy nhiên, forEach()thực sự là một phương thức mảng, vì vậy nó chỉ có thể được sử dụng riêng với mảng. Cũng không có cách nào để dừng hoặc phá vỡ một vòng lặp forEach. Nếu bạn cần loại hành vi đó trong vòng lặp của mình, bạn sẽ phải sử dụng vòng lặp cơ bản.

Cho ... của vòng lặp

Các cho ... của vòng lặp được sử dụng để lặp qua bất kỳ loại dữ liệu đó là iterable.

Thí dụ:

const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

for (const digit of digits) {
  console.log(digit);
}

Bản in:

0

1

2

3

4

5

6

7

số 8

9

Điều này làm cho ... vòng lặp trở thành phiên bản ngắn gọn nhất của tất cả các vòng lặp.

Nhưng xin chờ chút nữa! Vòng lặp for ... của vòng lặp cũng có một số lợi ích bổ sung giúp khắc phục các điểm yếu của vòng lặp for và for ... trong các vòng lặp.

Bạn có thể dừng hoặc ngắt một ... vòng lặp bất cứ lúc nào.

const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

for (const digit of digits) {
  if (digit % 2 === 0) {
    continue;
  }
  console.log(digit);
}

Bản in:

1

3

5

7

9

Và bạn không phải lo lắng về việc thêm thuộc tính mới vào các đối tượng. Vòng lặp for ... của vòng lặp sẽ chỉ lặp lại các giá trị trong đối tượng.


2
" Vòng lặp for ... trong vòng cải thiện các điểm yếu của vòng lặp for bằng cách loại bỏ logic đếm và điều kiện thoát " - không, đó không phải là điều nó làm. Không có gì.
Bergi

1
@Bergi Bạn có thể làm rõ lý do tại sao bạn nghĩ rằng đó không phải là những gì nó làm, và những gì bạn thực sự nghĩ rằng nó cải thiện?
Elar

2
Nó không cải thiện bất cứ điều gì, nó có lý do riêng. Nó thực hiện một cái gì đó hoàn toàn khác với một for (var index=0; index<arr.length; index++)vòng lặp (trong đó bộ indexđếm là một số nguyên, không giống như trong ví dụ của bạn).
Bergi

làm cho nó khó hiểu rằng các giá trị mảng bạn chọn cho ví dụ tương ứng với các giá trị chỉ số mảng ...
Sergey

20

Sự khác biệt for..infor..of:

Cả hai for..infor..oflà các cấu trúc lặp được sử dụng để lặp trên các cấu trúc dữ liệu. Sự khác biệt duy nhất là so với những gì họ lặp đi lặp lại:

  1. for..inLặp lại trên tất cả các khóa thuộc tính vô số của một đối tượng
  2. for..oflặp qua các giá trị của một đối tượng lặp. Ví dụ về các đối tượng lặp là các mảng, chuỗi và NodeLists.

Thí dụ:

let arr = ['el1', 'el2', 'el3'];

arr.addedProp = 'arrProp';

// elKey are the property keys
for (let elKey in arr) {
  console.log(elKey);
}

// elValue are the property values
for (let elValue of arr) {
  console.log(elValue)
}

Trong ví dụ này, chúng ta có thể quan sát rằng for..invòng lặp lặp trên các khóa của đối tượng, là một đối tượng mảng trong ví dụ này. Các khóa là 0, 1, 2 tương ứng với các phần tử mảng mà chúng ta đã thêm và addedProp. Đây là cách arrđối tượng mảng trông trong chrome devtools:

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

Bạn thấy rằng for..invòng lặp của chúng tôi không làm gì khác hơn là chỉ lặp đi lặp lại các giá trị này.


Các for..ofvòng lặp trong ví dụ của chúng ta lặp qua các giá trị của một cấu trúc dữ liệu. Các giá trị trong ví dụ cụ thể này là 'el1', 'el2', 'el3'. Các giá trị mà cấu trúc dữ liệu có thể lặp lại sẽ sử dụng for..ofphụ thuộc vào loại đối tượng lặp. Ví dụ, một mảng sẽ trả về các giá trị của tất cả các phần tử mảng trong khi một chuỗi trả về mỗi ký tự riêng lẻ của chuỗi.


8

Câu for...inlệnh lặp lại các thuộc tính vô số của một đối tượng, theo thứ tự tùy ý. Các thuộc tính có thể đếm được là các thuộc tính có cờ [[Có thể đếm được]] được đặt thành đúng, do đó nếu có bất kỳ thuộc tính nào trong chuỗi nguyên mẫu, for...invòng lặp cũng sẽ lặp lại trên các thuộc tính đó.

Câu for...oflệnh lặp lại trên dữ liệu mà đối tượng lặp có thể định nghĩa được lặp lại.

Thí dụ:

Object.prototype.objCustom = function() {}; 
Array.prototype.arrCustom = function() {};

let iterable = [3, 5, 7];

for (let i in iterable) {
  console.log(i); // logs: 0, 1, 2, "arrCustom", "objCustom"
}

for (let i in iterable) {
  if (iterable.hasOwnProperty(i)) {
    console.log(i); // logs: 0, 1, 2,
  }
}

for (let i of iterable) {
  console.log(i); // logs: 3, 5, 7
}

Giống như trước đó, bạn có thể bỏ qua việc thêm hasOwnPropertyvào for...ofcác vòng lặp.


7

Câu lệnh for-in lặp đi lặp lại trên các thuộc tính có thể đếm được của một đối tượng, theo thứ tự tùy ý.

Vòng lặp sẽ lặp lại trên tất cả các thuộc tính có thể đếm được của chính đối tượng và các đối tượng đó kế thừa từ nguyên mẫu của hàm tạo của nó

Về cơ bản, bạn có thể nghĩ nó là "for in" lặp lại và liệt kê ra tất cả các khóa.

var str = 'abc';
var arrForOf = [];
var arrForIn = [];

for(value of str){
  arrForOf.push(value);
}

for(value in str){
  arrForIn.push(value);
}

console.log(arrForOf); 
// ["a", "b", "c"]
console.log(arrForIn); 
// ["0", "1", "2", "formatUnicorn", "truncate", "splitOnLast", "contains"]

for in sẽ chỉ hiển thị các khóa nếu chúng được thêm bởi chúng tôi, nó sẽ không hiển thị định dạngUnicorn
Milad

1
"formatUnicorn", "truncate", "splitOnLast", "chứa" in ra vì ghi đè stackoverflow String.prototype.
jasonxia23

6

Có một số kiểu dữ liệu đã được xác định cho phép chúng ta lặp lại chúng một cách dễ dàng, ví dụ: Array, Map, String Object

Bình thường đối với các lần lặp qua iterator và trong phản hồi cung cấp cho chúng ta các khóa theo thứ tự chèn như trong ví dụ dưới đây.

  const numbers = [1,2,3,4,5];
   for(let number in number) {
     console.log(number);
   }

   // result: 0, 1, 2, 3, 4

Bây giờ nếu chúng ta thử tương tự với for , thì trong phản hồi, nó cung cấp cho chúng ta các giá trị không phải là các khóa. ví dụ

  const numbers = [1,2,3,4,5];
   for(let numbers of numbers) {
    console.log(number);
  }

  // result: 1, 2, 3, 4, 5

Vì vậy, nhìn vào cả hai trình lặp, chúng ta có thể dễ dàng phân biệt sự khác biệt giữa cả hai.

Lưu ý: - Đối với các chỉ làm việc với các Symbol.iterator

Vì vậy, nếu chúng ta cố gắng lặp lại trên đối tượng bình thường, thì nó sẽ cho chúng ta một lỗi, ví dụ như-

const Room = {
   area: 1000,
   height: 7,
   floor: 2
 }

for(let prop in Room) {
 console.log(prop);
 } 

// Result area, height, floor

for(let prop of Room) {
  console.log(prop);
 } 

Phòng không thể lặp lại

Bây giờ để lặp lại, chúng ta cần xác định ES6 Symbol.iterator, vd

  const Room= {
    area: 1000, height: 7, floor: 2,
   [Symbol.iterator]: function* (){
    yield this.area;
    yield this.height;
    yield this.floors;
  }
}


for(let prop of Room) {
  console.log(prop);
 } 

//Result 1000, 7, 2

Đây là sự khác biệt giữa For inFor of . Hy vọng rằng nó có thể làm rõ sự khác biệt.


5

Một điểm khác biệt giữa hai vòng lặp, điều mà chưa ai từng đề cập trước đây:

Phá hủy for...inđược phản đối. Sử dụng for...ofthay thế.

Nguồn

Vì vậy, nếu chúng ta muốn sử dụng hàm hủy trong một vòng lặp, để có được cả chỉ sốgiá trị của từng phần tử mảng , chúng ta nên sử dụng for...ofvòng lặp với phương thức Arrayentries() :

for (const [idx, el] of arr.entries()) {
    console.log( idx + ': ' + el );
}

1
Có @GalMargalit, tôi đọc nó một cách cẩn thận. Tôi đồng ý rằng điều đó for each...inkhông được chấp nhận (điểm đầu tiên), nhưng tôi đã không viết về nó ... Tôi đã viết rằng "Phá hủy for...inbị phản đối. for...ofThay vào đó hãy sử dụng ." (điểm thứ hai): developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ mẹo Bạn có đồng ý với tôi @GalMargalit không?
simhumileco

1
Haha bạn nói đúng, tôi đã không đọc kỹ! Đúng, về cơ bản, tôi đã suy nghĩ điều tương tự và nghĩ rằng bạn đang đề cập đến một điều khác.
Gal Margalit

2

Mọi người đã giải thích lý do tại sao vấn đề này xảy ra, nhưng vẫn rất dễ quên nó và sau đó gãi đầu tại sao bạn nhận được kết quả sai. Đặc biệt là khi bạn đang làm việc trên các tập dữ liệu lớn khi kết quả có vẻ ổn ngay từ cái nhìn đầu tiên.

Sử dụng Object.entriesbạn đảm bảo để đi tất cả các thuộc tính:

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

for ( var [key, val] of Object.entries( arr ) ) {
   console.log( val );
}

/* Result:

3
5
7
hello

*/

2

A thấy rất nhiều câu trả lời hay, nhưng tôi quyết định đặt 5 xu của mình chỉ để có ví dụ hay:

Cho trong vòng lặp

lặp đi lặp lại trên tất cả các đạo cụ

let nodes = document.documentElement.childNodes;

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

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

lặp đi lặp lại trên tất cả các giá trị lặp

let nodes = document.documentElement.childNodes;

for (var node of nodes) {
  console.log( node.toString() );
}


2

Khi tôi lần đầu tiên bắt đầu học tạicác vòng lặp , tôi đã nhầm lẫn với sản lượng của tôi cũng vậy, nhưng với một vài nghiên cứu và tìm hiểu bạn có thể nghĩ đến vòng lặp cá nhân như sau: Các

  1. cho ... trong vòng lặp trả về các chỉ mục của thuộc tính riêng lẻ và không có tác động đến giá trị của thuộc tính , nó lặp và trả về thông tin về thuộc tính chứ không phải giá trị . Ví dụ

let profile = { name : "Naphtali", age : 24, favCar : "Mustang", favDrink : "Baileys" }

Đoạn mã trên chỉ là tạo một đối tượng được gọi là hồ sơ , chúng tôi sẽ sử dụng nó cho cả các ví dụ của chúng tôi , vì vậy, đừng nhầm lẫn khi bạn nhìn thấy đối tượng hồ sơ trên một ví dụ, chỉ cần biết nó đã được tạo.

Vì vậy, bây giờ chúng ta hãy sử dụng vòng lặp for ... bên dưới

for(let myIndex in profile){
    console.log(`The index of my object property is ${myIndex}`)
}
 // Outputs : 
        The index of my object property is 0
        The index of my object property is 1
        The index of my object property is 2
        The index of my object property is 3

Bây giờ Lý do cho đầu ra là chúng ta có Bốn (4) thuộc tính trong đối tượng hồ sơ của mình và lập chỉ mục như chúng ta đều biết bắt đầu từ 0 ... n , vì vậy, chúng ta có được chỉ số của các thuộc tính 0,1,2,3 kể từ khi chúng ta làm việc với vòng lặp for..in .

  1. cho ... của vòng lặp * có thể trả về thuộc tính , giá trị hoặc cả hai , Hãy xem cách làm. Trong javaScript, chúng ta không thể lặp qua các đối tượng một cách bình thường như trên các mảng, vì vậy, có một vài yếu tố chúng ta có thể sử dụng để truy cập vào một trong các lựa chọn của mình từ một đối tượng.

    • Object.keys ( tên đối tượng-đi-đây ) >>> Trả về các khóa hoặc thuộc tính của một đối tượng.

    • Object.values ( object-name-go-here ) >>> Trả về các giá trị của một đối tượng.

    • Object.entries ( object-name-đi-ở đây ) >>> Returns cả các phímcác giá trị của một đối tượng.

Dưới đây là các ví dụ về cách sử dụng của chúng, hãy chú ý đến Object.entries () :

Step One: Convert the object to get either its key, value, or both.
Step Two: loop through.


// Getting the keys/property

   Step One: let myKeys = ***Object.keys(profile)***
   Step Two: for(let keys of myKeys){
             console.log(`The key of my object property is ${keys}`)
           }

// Getting the values of the property

    Step One: let myValues = ***Object.values(profile)***
    Step Two : for(let values of myValues){
                 console.log(`The value of my object property is ${values}`)
               }

Khi sử dụng Object.entries () có nghĩa là bạn đang gọi hai mục trên đối tượng, tức là các khóa và giá trị. Bạn có thể gọi cả hai bằng một trong hai mục. Ví dụ dưới đây.

Step One: Convert the object to entries, using ***Object.entries(object-name)***
Step Two: **Destructure** the ***entries object which carries the keys and values*** 
like so **[keys, values]**, by so doing, you have access to either or both content.


    // Getting the keys/property

       Step One: let myKeysEntry = ***Object.entries(profile)***
       Step Two: for(let [keys, values] of myKeysEntry){
                 console.log(`The key of my object property is ${keys}`)
               }

    // Getting the values of the property

        Step One: let myValuesEntry = ***Object.entries(profile)***
        Step Two : for(let [keys, values] of myValuesEntry){
                     console.log(`The value of my object property is ${values}`)
                   }

    // Getting both keys and values

        Step One: let myBothEntry = ***Object.entries(profile)***
        Step Two : for(let [keys, values] of myBothEntry){
                     console.log(`The keys of my object is ${keys} and its value 
is ${values}`)
                   }

Nhận xét về phần không rõ ràng (s).


1

các for-invòng lặp

for-invòng lặp được sử dụng để duyệt qua các thuộc tính có thể đếm được của một tập hợp, theo thứ tự tùy ý . Bộ sưu tập là một đối tượng loại container có các mục có thể sử dụng chỉ mục hoặc khóa.

var myObject = {a: 1, b: 2, c: 3};
var myArray = [1, 2, 3];
var myString = "123";

console.log( myObject[ 'a' ], myArray[ 1 ], myString[ 2 ] );

for-inloop chiết xuất đếm tài sản ( phím ) của một bộ sưu tập tất cả cùng một lúc và lặp trên nó cùng một lúc. Một thuộc tính vô số là thuộc tính của một bộ sưu tập có thể xuất hiện trong for-invòng lặp.

Theo mặc định, tất cả các thuộc tính của một mảng và đối tượng xuất hiện trong for-invòng lặp. Tuy nhiên, chúng ta có thể sử dụng phương thức Object.defineProperty để cấu hình thủ công các thuộc tính của bộ sưu tập.

var myObject = {a: 1, b: 2, c: 3};
var myArray = [1, 2, 3];

Object.defineProperty( myObject, 'd', { value: 4, enumerable: false } );
Object.defineProperty( myArray, 3, { value: 4, enumerable: false } );

for( var i in myObject ){ console.log( 'myObject:i =>', i ); }
for( var i in myArray ){ console.log( 'myArray:i  =>', i ); }

Trong ví dụ trên, thuộc tính dcủa myObjectvà chỉ mục 3của myArraykhông xuất hiện trong for-invòng lặp vì chúng được cấu hình với enumerable: false.

Có một vài vấn đề với for-incác vòng lặp. Trong trường hợp Mảng, for-invòng lặp cũng sẽ xem xét methodsthêm vào mảng bằng myArray.someMethod = fcú pháp, tuy nhiên, myArray.lengthvẫn còn 4.

các for-ofvòng lặp

Đó là một quan niệm sai lầm for-oflặp đi lặp lại trên các giá trị của một bộ sưu tập. for-ofvòng lặp lặp trên một Iterableđối tượng. Một iterable là một đối tượng có phương thức với tên Symbol.iteratortrực tiếp trên một trong các nguyên mẫu của nó.

Symbol.iteratorphương thức sẽ trả về một Iterator . Một iterator là một đối tượng có một nextphương thức. Phương thức này khi được gọi là return valuedone property.

Khi chúng ta lặp một iterable đối tượng sử dụng for-ofvòng lặp, các Symbol.iteratorphương pháp này sẽ được gọi là một lần nhận được một iterator đối tượng. Đối với mỗi lần lặp của for-ofvòng lặp, nextphương thức của đối tượng lặp này sẽ được gọi cho đến khi donetrả về bởi lệnh next()gọi trả về false. Giá trị nhận được bởi for-ofvòng lặp cho mỗi lần lặp nếu thuộc valuetính được trả về bởi next()cuộc gọi.

var myObject = { a: 1, b: 2, c: 3, d: 4 };

// make `myObject` iterable by adding `Symbol.iterator` function directlty on it
myObject[ Symbol.iterator ] = function(){
  console.log( `LOG: called 'Symbol.iterator' method` );
  var _myObject = this; // `this` points to `myObject`
  
  // return an iterator object
  return {
    keys: Object.keys( _myObject ), 
    current: 0,
    next: function() {
      console.log( `LOG: called 'next' method: index ${ this.current }` );
      
      if( this.current === this.keys.length ){
        return { done: true, value: null }; // Here, `value` is ignored by `for-of` loop
      } else {
        return { done: false, value: _myObject[ this.keys[ this.current++ ] ] };
      }
    }
  };
}

// use `for-of` loop on `myObject` iterable
for( let value of myObject ) {
  console.log( 'myObject: value => ', value );
}

Các for-ofvòng lặp là mới trong ES6 và như vậy là IterableIterables . Kiểu Arrayconstructor có Symbol.iteratorphương thức trên nguyên mẫu của nó. Nhà Objectxây dựng đáng buồn là không có nó Object.keys(), Object.values()và, Object.entries()các phương thức trả về một lần lặp ( bạn có thể sử dụng console.dir(obj)để kiểm tra các phương thức nguyên mẫu ). Lợi ích của for-ofvòng lặp là bất kỳ đối tượng nào cũng có thể được lặp lại, thậm chí là tùy chỉnh DogAnimalcác lớp của bạn .

Cách dễ dàng để tạo một đối tượng có thể lặp là bằng cách triển khai ES6 Generator thay vì thực hiện trình lặp tùy chỉnh.

Không giống như for-in, for-ofvòng lặp có thể đợi một tác vụ không đồng bộ hoàn thành trong mỗi lần lặp. Điều này đạt được bằng cách sử dụng awaittừ khóa sau khi tài liệufor tuyên bố .

Một điều tuyệt vời khác về for-ofvòng lặp là nó có hỗ trợ Unicode. Theo thông số kỹ thuật ES6, các chuỗi được lưu trữ với mã hóa UTF-16. Do đó, mỗi nhân vật có thể mất một 16-bithoặc 32-bit. Theo truyền thống, các chuỗi được lưu trữ với mã hóa UCS-2 có hỗ trợ cho các ký tự chỉ có thể được lưu trữ trong phạm vi 16 bits.

Do đó, String.lengthtrả về số lượng 16-bitkhối trong một chuỗi. Các nhân vật hiện đại như một nhân vật Emoji mất 32 bit. Do đó, ký tự này sẽ trả lengthvề 2. for-invòng lặp lặp qua 16-bitcác khối và trả về sai index. Tuy nhiên, for-ofvòng lặp lặp qua ký tự riêng dựa trên thông số kỹ thuật UTF-16.

var emoji = "😊🤣";

console.log( 'emoji.length', emoji.length );

for( var index in emoji ){ console.log( 'for-in: emoji.character', emoji[index] ); }
for( var character of emoji ){ console.log( 'for-of: emoji.character', character ); }


0

Tôi thấy lời giải thích sau đây từ https://javascript.info/array rất hữu ích:

Một trong những cách lâu đời nhất để xoay vòng các mục mảng là vòng lặp for trên các chỉ mục:

let arr = ["Apple", "Orange", "Pear"];

for (let i = 0; i < arr.length; i++) { alert( arr[i] ); } But for arrays there is another form of loop, for..of:

let fruits = ["Apple", "Orange", "Plum"];

// iterates over array elements for (let fruit of fruits) { alert( fruit ); } The for..of doesn’t give access to the number of the current element, just its value, but in most cases that’s enough. And it’s shorter.

Về mặt kỹ thuật, vì mảng là đối tượng, nên cũng có thể sử dụng cho..in:

let arr = ["Apple", "Orange", "Pear"];

for (let key in arr) { alert( arr[key] ); // Apple, Orange, Pear } But that’s actually a bad idea. There are potential problems with it:

Vòng lặp for..in lặp lại trên tất cả các thuộc tính, không chỉ các số.

Có cái gọi là các đối tượng giống như mảng trong các trình duyệt và trong các môi trường khác, trông giống như các mảng. Đó là, chúng có các thuộc tính độ dài và chỉ mục, nhưng chúng cũng có thể có các thuộc tính và phương thức không phải là số khác mà chúng ta thường không cần. Vòng lặp for..in sẽ liệt kê chúng mặc dù. Vì vậy, nếu chúng ta cần phải làm việc với các đối tượng giống như mảng, thì các thuộc tính này có thể trở thành một vấn đề.

Vòng lặp for..in được tối ưu hóa cho các đối tượng chung, không phải mảng và do đó chậm hơn 10 - 100 lần. Tất nhiên, nó vẫn rất nhanh. Việc tăng tốc chỉ có thể là vấn đề trong các nút cổ chai. Nhưng chúng ta vẫn nên nhận thức được sự khác biệt.

Nói chung, chúng ta không nên sử dụng cho..in cho mảng.


0

Dưới đây là một ghi nhớ hữu ích để ghi nhớ sự khác biệt giữa for...inVòng lặp và for...ofVòng lặp.

"chỉ mục trong, đối tượng của"

for...in Loop=> lặp qua chỉ mục trong mảng.

for...of Loop=> lặp đi lặp lại trên đối tượng của các đối tượng.

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.