Jaka jest różnica między (dla… w) a (dla… z) instrukcji w JavaScript?

409

Wiem, co to jest for... inpętla (iteruje się po kluczu), ale usłyszałem po raz pierwszy o for... of(iteruje się po wartości).

Jestem zmieszany z for... ofpętlą. Nie dostałem przymiotnika. Oto kod poniżej:

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"
}

Mam for... ofiterację wartości nieruchomości. Dlaczego więc nie loguje się (nie zwraca) "3", "5", "7", "hello"zamiast "3", "5", "7"? ale for... inpętla iteruje się po każdym klawiszu ( "0", "1", "2", "foo"). for... inPętla tutaj również iteruje się po fookluczu. Ale for... ofnie przechodzi przez wartość foonieruchomości, tj "hello". Dlaczego tak jest?

Krótka historia w skrócie:

Tutaj konsola for... ofpętli. Powinien się zalogować, "3", "5", "7","hello"ale tutaj loguje się "3", "5", "7". Dlaczego ?

Przykładowy link

Mukund Kumar
źródło
1
w przypadku, gdy tęsknisz, oto link początkowy developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Anthony Russell
1
O ile rozumiem, for ... ofzostał wprowadzony do języka, aby rozwiązać problemy z używaniem for ... intablic. Array.prototypemoże zostać zmieniony w taki sposób, że dostępne są dodatkowe właściwości, co sprawia, że ​​ich iteracja jest niebezpieczna, ponieważ można uzyskać klucze nienumeryczne, których się nie spodziewałeś.
Filogeneza
2
Dla przyszłych czytelników: prawdopodobnie nie jest to duplikat słowa kluczowego JavaScript of(dla… pętli) , ponieważ pyta o konkretne zachowanie funkcji, zamiast prosić o ogólny przegląd.
apsillers
2
Przyzwyczaj się do mówienia „ for <key> in” i „ for <value> of” i zdaj sobie sprawę, że IE nie obsługujefor..of
BotNet
Świetny artykuł o
wyliczalnym

Odpowiedzi:

304

for in zapętla się nad wymiennymi nazwami właściwości obiektu.

for of(nowość w ES6) używa iteratora specyficznego dla obiektu i zapętla wartości generowane przez to.

W twoim przykładzie iterator tablicy zwraca wszystkie wartości w tablicy (ignorując właściwości nieindeksowane).

Bergi
źródło
9
for ... ofjest znormalizowany w ES6.
Justin,
2
To dziwne, przysięgam, że gdzieś przeczytałem, że został przeniesiony z powrotem do ES7, ale najwyraźniej to nie była prawda. Mój błąd.
Alexander O'Mara,
40
Mnemoniczny: obiekty „o” -> nie „o”, „i” -> nie „i”
Placoplatr
4
inny mnemonik: for... of:: tablice :: tablice zawsze mają długość, więc możesz pomyśleć for.. [n-ty element] of.. [q elementów]
Nathan Smith
14
Kolejne mnemoniczne ... for..in..keys=== klucze obce === użyj for...indla kluczy! Jako takie użyj for...ofwartości.
Gunther
237

Pełną odpowiedź znajduję na stronie : https://www.typescriptlang.org/docs/handbook/iterators-and-generators.html (Mimo że jest to skrypt typu, to samo dotyczy javascript)

Oba for..ofi for..ininstrukcje powtarzają się po listach; wartości iterowane są różne, for..inzwraca listę kluczy iterowanego obiektu, natomiast for..ofzwraca listę wartości liczbowych właściwości iterowanego obiektu.

Oto przykład, który pokazuje to rozróżnienie:

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"
}

Kolejne rozróżnienie polega na tym, że for..in działa na dowolnym obiekcie; służy jako sposób na sprawdzenie właściwości tego obiektu. for..ofz drugiej strony interesuje się głównie wartościami obiektów iterowalnych. Wbudowane obiekty, takie jak Map i Set, implement Symbol.iteratorumożliwiają dostęp do przechowywanych wartości.

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"
}
Alireza Fattahi
źródło
1
Co więcej, wywołanie czegoś takiego jak (niech I z {}) {console.log (i); } wyrzuci błąd TypeError: VM391: 1 Nieprzechwycony błąd TypeError: {} nie można iterować w <anonimowy>: 1: 14, przynajmniej w Chrome
kboom
TS za zwycięstwo - przykład jest niepoprawny, ten ostatni powinien zwrócić „ssaki”, a nie // „Kot”, „Pies”, „Chomik”
martinp999
8
Pamiętam to przez: dla „in” dla index. I wtedy „z” będzie oznaczeniem valueskażdego indeksu / klucza / pozycji.
SherylHohman
Fajnie, to będzie dla mnie królem: za pomocą for-ins do iteracji przedmiotów zwykle muszę stworzyć let thisItem = items[all];zmienną, for...ofpomaga to skrócić!
Vasily Hall
Pamiętam to: for...injak Object.keys(), zgadnij co? Tablice są obiektami, które również zwracają swoje nieprzyzwoitości. :)
Sujeet Agrahari
38

Dla ... w pętli

Dla ... w pętli poprawia na słabości do pętli poprzez eliminację logikę liczenia i stan wyjścia.

Przykład:

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

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

Ale nadal musisz poradzić sobie z problemem korzystania z indeksu, aby uzyskać dostęp do wartości tablicy, i to śmierdzi; prawie sprawia, że ​​jest to bardziej mylące niż wcześniej.

Pętla for ... in może sprawić kłopoty, gdy trzeba dodać dodatkową metodę do tablicy (lub innego obiektu). Ponieważ dla ... w pętlach pętla nad wszystkimi wyliczalnymi właściwościami oznacza to, że jeśli dodasz jakieś dodatkowe właściwości do prototypu tablicy, wówczas te właściwości pojawią się również w pętli.

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

Wydruki:

0

1

2)

3)

4

5

6

7

8

9

function () {for (niech i = 0; i <this.length; i ++) {this [i] = this [i] .toFixed (2); }}

Dlatego dla ... w pętlach odradza się zapętlanie tablic.

UWAGA : Pętla forEach jest innym rodzajem pętli for w JavaScript. Jednak forEach()w rzeczywistości jest metoda array, dzięki czemu może być stosowany tylko wyłącznie z tablicami. Nie ma również sposobu na zatrzymanie lub przerwanie pętli forEach. Jeśli potrzebujesz tego rodzaju zachowania w swojej pętli, będziesz musiał użyć podstawowej pętli for.

Dla ... pętli

Dla ... od pętli jest używany do pętli nad wszelkiego rodzaju danych, które są iterable.

Przykład:

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

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

Wydruki:

0

1

2)

3)

4

5

6

7

8

9

To sprawia, że ​​pętla for ... jest najbardziej zwięzłą wersją wszystkich pętli for.

Ale czekaj, jest więcej! Pętla for ... ma również dodatkowe zalety, które naprawiają słabości pętli for i for ...

W każdej chwili możesz zatrzymać lub przerwać ... pętlę.

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

Wydruki:

1

3)

5

7

9

I nie musisz się martwić o dodanie nowych właściwości do obiektów. Pętla for ... zapętla tylko wartości w obiekcie.

Elar
źródło
2
Pętla for… poprawia słabości pętli for, eliminując logikę liczenia i warunek wyjścia ” - nie, to nie to. Ani trochę.
Bergi,
1
@Bergi Czy mógłbyś wyjaśnić, dlaczego uważasz, że to nie to, co robi, i na czym tak naprawdę myślisz, że się poprawia?
Elar,
2
Niczego się nie poprawia, ma swoją rację bytu. Robi coś zupełnie innego niż for (var index=0; index<arr.length; index++)pętla (gdzie indexlicznik jest liczbą całkowitą, inaczej niż w twoim przykładzie).
Bergi,
sprawia, że ​​mylące jest to, że wartości tablicy wybrane w przykładzie odpowiadają wartościom indeksu tablicy ...
Sergey
19

Różnica for..ini for..of:

Zarówno for..ini for..ofsą przelotowe konstrukcje, które są wykorzystywane do iteracji nad strukturami danych. Jedyna różnica polega na tym, co iterują:

  1. for..initeruje wszystkie wyliczalne klucze właściwości obiektu
  2. for..ofiteruje nad wartościami obiektu iterowalnego. Przykładami obiektów iterowalnych są tablice, łańcuchy i NodeLists.

Przykład:

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

W tym przykładzie możemy zaobserwować, że for..inpętla iteruje po kluczach obiektu, który w tym przykładzie jest obiektem tablicowym. Kluczami są 0, 1, 2, które odpowiadają dodanym elementom tablicy i addedProp. Tak arrwygląda obiekt tablicy w chrome devtools:

wprowadź opis zdjęcia tutaj

Widzisz, że nasza for..inpętla robi tylko iterację tych wartości.


for..ofPętli przykładzie iteruje się wartości w strukturze danych. Wartości w tym konkretnym przykładzie to 'el1', 'el2', 'el3'. Wartości, z których zwróci iterowalna struktura danych, for..ofzależą od typu iterowalnego obiektu. Na przykład tablica zwraca wartości wszystkich elementów tablicy, podczas gdy łańcuch zwraca każdy indywidualny znak łańcucha.

Willem van der Veen
źródło
8

for...inOświadczenie iteracje nad przeliczalna właściwości obiektu, w dowolnej kolejności. Wyliczalne właściwości to te właściwości, których wewnętrzna flaga [[Enumerable]] jest ustawiona na wartość true, dlatego jeśli w łańcuchu prototypów znajduje się jakaś wyliczalna właściwość, for...inpętla również będzie iterować.

for...ofOświadczenie iteruje dane iterable obiekt określa należy powtórzyć na drugą.

Przykład:

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
}

Tak jak wcześniej, możesz pominąć dodawanie hasOwnPropertyw for...ofpętlach.

Ramandeep Sohi
źródło
7

Instrukcja for-in iteruje po policzalnych właściwościach obiektu w dowolnej kolejności.

Pętla będzie iterować wszystkie wyliczalne właściwości samego obiektu i tych, które dziedziczy po prototypie konstruktora

Możesz myśleć o tym jako o „na wejściu” w zasadzie iteruje i wypisuje wszystkie klucze.

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"]
Devdutta Natu
źródło
for in pokaże klucze tylko jeśli zostaną przez nas dodane, nie wyświetli formatu Jednorożec
Milad
1
Wydrukuj „formatUnicorn”, „obcinaj”, „splitOnLast”, „zawiera”, ponieważ zastępuje przepełnienie stosu String.prototype.
jasonxia23
6

Istnieją już zdefiniowane typy danych, które pozwalają na łatwe iterowanie nad nimi, np. Array, Map, String Objects

Normalne dla iteracji nad iteratorem iw odpowiedzi dostarcza nam klucze, które są w kolejności wstawiania, jak pokazano w poniższym przykładzie.

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

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

Teraz, jeśli spróbujemy tego samego z for , to w odpowiedzi dostarczy nam wartości, a nie klucze. na przykład

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

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

Patrząc na oba iteratory, możemy łatwo odróżnić różnicę między nimi.

Uwaga: - For of działa tylko z Symbol.iterator

Więc jeśli spróbujemy wykonać iterację nad normalnym obiektem, to da nam błąd, np.

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

Pokój nie jest powtarzalny

Teraz w celu iteracji musimy zdefiniować ES6 Symbol.iterator np

  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

To jest różnica między For in a For of . Mam nadzieję, że to wyjaśni różnicę.

Amit Mundra
źródło
5

Kolejna różnica między dwiema pętlami, o której nikt wcześniej nie wspominał:

Destrukturyzacja for...injest przestarzała. Użyj for...ofzamiast tego.

Źródło

Więc jeśli chcemy użyć destrukcji w pętli, w celu uzyskania zarówno indeksu, jak i wartości każdego elementu tablicy , powinniśmy użyć for...ofpętli z metodą Arrayentries() :

for (const [idx, el] of arr.entries()) {
    console.log( idx + ': ' + el );
}
simhumileco
źródło
1
Tak @GalMargalit, uważnie to przeczytałem. Zgadzam się, że to for each...injest przestarzałe (pierwszy punkt), ale nie pisałem o tym ... Napisałem, że „Destrukturyzacja for...injest przestarzała. Użyj for...ofzamiast tego”. (drugi punkt): developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Czy zgadzasz się ze mną @GalMargalit?
simhumileco
1
Haha masz rację, nie czytałem uważnie! To prawda, że ​​zasadniczo myślałem o tym samym i pomyślałem, że masz na myśli inną.
Gal Margalit
2

Wszyscy wyjaśnili, dlaczego ten problem występuje, ale nadal bardzo łatwo o nim zapomnieć, a następnie podrapać się w głowę, dlaczego otrzymałeś złe wyniki. Zwłaszcza, gdy pracujesz nad dużymi zestawami danych, gdy wyniki wydają się na pierwszy rzut oka dobre.

Za pomocą Object.entriesupewnij się, aby przejść przez wszystkie właściwości:

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

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

/* Result:

3
5
7
hello

*/
David C.
źródło
2

Widzę wiele dobrych odpowiedzi, ale postanawiam postawić moje 5 centów, aby mieć dobry przykład:

Do pętli

iteruje wszystkie wyliczalne rekwizyty

let nodes = document.documentElement.childNodes;

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

For of loop

iteruje wszystkie wartości iterowalne

let nodes = document.documentElement.childNodes;

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

WebBrother
źródło
2

Kiedy po raz pierwszy zacząłem uczyć się pętli for in i loop , byłem również zdezorientowany z moją wydajnością, ale z kilkoma badaniami i zrozumieniem możesz pomyśleć o indywidualnej pętli w następujący sposób:

  1. for ... w pętli zwraca indeksy poszczególnych właściwości i nie ma wpływu na wartość właściwości , zapętla i zwraca informacje o właściwości, a nie wartości . Na przykład

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

Powyższy kod tworzy tylko obiekt o nazwie profil , użyjemy go w obu naszych przykładach , więc nie myl się, gdy zobaczysz obiekt profilu na przykładzie, po prostu wiedz, że został utworzony.

Teraz skorzystajmy z pętli for ... in poniżej

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

Powodem tego jest fakt, że mamy cztery właściwości (4) w naszym obiekcie profilu, a indeksowanie, jak wszyscy wiemy, zaczyna się od 0 ... n , więc otrzymujemy indeks właściwości 0,1,2,3, ponieważ jesteśmy praca z pętlą for..in .

  1. dla ... pętli * może zwrócić właściwość , wartość lub oba , Spójrzmy jak. W javaScript nie możemy normalnie zapętlać obiektów, tak jak w przypadku tablic, więc istnieje kilka elementów, których możemy użyć, aby uzyskać dostęp do jednego z naszych wyborów z obiektu.

    • Object.keys ( nazwa-obiektu-idzie-tutaj ) >>> Zwraca klucze lub właściwości obiektu.

    • Object.values ( nazwa-obiektu-idzie-tutaj ) >>> Zwraca wartości obiektu.

    • Object.entries ( object-name-idzie-tu ) >>> Powroty oba te klucze i wartości obiektu.

Poniżej znajdują się przykłady ich użycia, zwróć uwagę na 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}`)
               }

Korzystając z Object.entries (), pamiętaj , że wywołujesz dwa wpisy na obiekcie, tj . Klucze i wartości. Możesz zadzwonić zarówno przez dowolny wpis. Przykład poniżej.

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}`)
                   }

Komentuj niejasne sekcje części.

Naphtali Duniya
źródło
1

for-inpętla

for-inPętla służy do przechodzenia przez wyliczalne właściwości kolekcji w dowolnej kolejności . Kolekcja to obiekt typu kontener, którego elementy mogą korzystać z indeksu lub klucza.

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-inPętla wyodrębnia wszystkie wyliczalne właściwości ( klucze ) kolekcji naraz i iteruje po niej pojedynczo. Wyliczalna właściwość jest właściwością kolekcji, która może pojawiać się w for-inpętli.

Domyślnie wszystkie właściwości macierzy i obiektu pojawiają się w for-inpętli. Możemy jednak użyć metody Object.defineProperty , aby ręcznie skonfigurować właściwości kolekcji.

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

W powyższym przykładzie, własność dz myObjecta wskaźnik 3z myArraynie pojawia się w for-inpętli, ponieważ są one skonfigurowane enumerable: false.

Istnieje kilka problemów z for-inpętlami. W przypadku tablic for-inpętla będzie również rozważać methodsdodanie do tablicy przy użyciu myArray.someMethod = fskładni, jednak myArray.lengthpozostaje 4.

for-ofpętla

Jest to nieporozumienie, które for-ofpowtarza iterację wartości kolekcji. for-ofpętla iteruje Iterableobiekt. Iterowalny to obiekt, który ma metodę z nazwą Symbol.iteratorbezpośrednio na niej na jednym ze swoich prototypów.

Symbol.iteratorMetoda powinna zwrócić Iterator . Iterator to obiekt posiadający nextmetodę. Ta metoda nazywa się return valuei donewłaściwości.

Kiedy iterujemy iterowalny obiekt za pomocą for-ofpętli, Symbol.iteratormetoda zostanie wywołana, gdy otrzymamy obiekt iteratora . Dla każdej iteracji for-ofpętli, nextmetoda tego obiektu iteratora zostanie wywołana aż donezwrócony przez next()fałszywe deklaracje połączeń. Wartość otrzymywana przez for-ofpętlę dla każdej iteracji, jeśli valuewłaściwość zwrócona przez next()wywołanie.

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

for-ofPętla jest nowy w ES6 i tak są iterable i Iterables . Typ Arraykonstruktora ma Symbol.iteratormetodę na swoim prototypie. ObjectKonstruktor niestety nie ma go jednak Object.keys(), Object.values()a Object.entries()metody zwracać iterable ( można użyć console.dir(obj)w celu sprawdzenia metody prototypów ). Zaletą for-ofpętli jest to, że każdy obiekt może być iterowalny, nawet twój niestandardowy Dogi Animalklasy.

Najłatwiejszym sposobem, aby obiekt był iterowalny, jest implementacja Generatora ES6 zamiast niestandardowej implementacji iteratora.

W przeciwieństwie do tego for-in, for-ofpętla może czekać na zakończenie zadania asynchronicznego w każdej iteracji. Osiąga się to za pomocą awaitsłowa kluczowego po dokumentacjifor instrukcji .

Kolejną wielką zaletą for-ofpętli jest obsługa Unicode. Zgodnie ze specyfikacjami ES6, ciągi są przechowywane z kodowaniem UTF-16. Stąd, każda postać może przybrać jedną 16-bitlub 32-bit. Tradycyjnie ciągi były przechowywane z kodowaniem UCS-2, które obsługuje znaki, które można przechowywać 16 bitstylko w obrębie .

Dlatego String.lengthzwraca liczbę 16-bitbloków w ciągu. Nowoczesne postacie, takie jak znak Emoji, mają 32 bity. Dlatego znak ten zwróci length2. for-inpętlę, iteruje się po 16-bitblokach i zwraca błąd index. Jednak for-ofpętla iteruje indywidualny znak na podstawie specyfikacji 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 ); }

Uday Hiwarale
źródło
0

Bardzo pomocne okazało się następujące wyjaśnienie z https://javascript.info/array :

Jednym z najstarszych sposobów przełączania elementów tablicy jest indeksowanie pętli for:

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.

Technicznie, ponieważ tablice są obiektami, możliwe jest również użycie dla ... w:

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:

Pętla dla ... in iteruje wszystkie właściwości, nie tylko numeryczne.

W przeglądarce i innych środowiskach znajdują się tak zwane „tablicowe” obiekty, które wyglądają jak tablice. Oznacza to, że mają właściwości długości i indeksów, ale mogą także mieć inne właściwości nienumeryczne i metody, których zwykle nie potrzebujemy. Pętla for..in wyświetli je jednak. Jeśli więc musimy pracować z obiektami podobnymi do tablicy, te „dodatkowe” właściwości mogą stać się problemem.

Pętla for..in jest zoptymalizowana dla obiektów ogólnych, a nie tablic, a zatem jest 10–100 razy wolniejsza. Oczywiście nadal jest bardzo szybki. Przyspieszenie może mieć znaczenie tylko w wąskich gardłach. Ale nadal powinniśmy być świadomi różnicy.

Zasadniczo nie powinniśmy używać dla ... w przypadku tablic.

Albert Leung
źródło
0

Oto przydatny mnemonik do zapamiętywania różnicy między for...inpętlą a for...ofpętlą.

„indeksuj, obiekt”

for...in Loop=> iteruje po indeksie w tablicy.

for...of Loop=> iteruje po obiekcie obiektów.

Bnieland
źródło