เหตุใดการใช้“ for … in” กับการทำซ้ำอาร์เรย์จึงเป็นความคิดที่ไม่ดี


1823

ฉันได้รับคำสั่งให้ไม่ใช้for...inกับอาร์เรย์ใน JavaScript ทำไมจะไม่ล่ะ?


45
ฉันเห็นคำถามล่าสุดที่มีคนพูดกับคุณ แต่พวกเขามีความหมายเฉพาะกับอาร์เรย์เท่านั้น มันถือว่าเป็นการปฏิบัติที่ไม่ดีสำหรับการวนซ้ำผ่านอาร์เรย์ แต่ไม่จำเป็นสำหรับการวนซ้ำผ่านสมาชิกของวัตถุ
mmurch

19
มีคำตอบมากมายสำหรับ "สำหรับ" ลูปเช่น 'สำหรับ (var i = 0; i <hColl.length; i ++) {}' เปรียบเทียบกับ 'var i = hColl.length; ในขณะที่ (i -) {} 'ซึ่งเมื่อเป็นไปได้ที่จะใช้แบบฟอร์มหลังมันจะเร็วกว่ามาก ฉันรู้ว่านี่คือวงสัมผัส แต่คิดว่าฉันจะเพิ่มบิตนี้
Mark Schultheiss

2
@ MarkSchultheiss แต่นั่นคือการทำซ้ำย้อนกลับ มีการทำซ้ำไปข้างหน้าอีกเวอร์ชันหนึ่งที่เร็วกว่าหรือไม่
ma11hew28

5
@Wandand ใช้var i = hCol1.length; for (i;i;i--;) {}แคช i เนื่องจากจะสร้างความแตกต่างและทำให้การทดสอบง่ายขึ้น - เบราว์เซอร์ที่เก่ากว่าความแตกต่างระหว่างforและwhileเสมอกับแคช "i" ตัวนับ - และแน่นอนว่าการลบไม่เหมาะกับสถานการณ์เสมอและค่าลบในขณะobfuscate ที่โค้ดบางบิตสำหรับบางคน และบันทึกvar i = 1000; for (i; i; i--) {}และvar b =1000 for (b; b--;) {}ที่ที่ฉันไป 1,000 ถึง 1 และ b ไปที่ 999 ถึง 0 - ยิ่งเบราว์เซอร์รุ่นเก่ามากขึ้น
Mark Schultheiss

9
คุณสามารถฉลาด for(var i = 0, l = myArray.length; i < l; ++i) ...เป็นวิธีที่เร็วที่สุดและดีที่สุดที่คุณจะได้รับเมื่อทำซ้ำไปข้างหน้า
Mathieu Amiot

คำตอบ:


1557

เหตุผลก็คือสิ่งก่อสร้างหนึ่ง:

var a = []; // Create a new empty array.
a[5] = 5;   // Perfectly legal JavaScript that resizes the array.

for (var i = 0; i < a.length; i++) {
    // Iterate over numeric indexes from 0 to 5, as everyone expects.
    console.log(a[i]);
}

/* Will display:
   undefined
   undefined
   undefined
   undefined
   undefined
   5
*/

บางครั้งอาจแตกต่างจากที่อื่นโดยสิ้นเชิง:

var a = [];
a[5] = 5;
for (var x in a) {
    // Shows only the explicitly set index of "5", and ignores 0-4
    console.log(x);
}

/* Will display:
   5
*/

นอกจากนี้ให้พิจารณาว่าไลบรารีJavaScriptอาจทำสิ่งนี้เช่นกันซึ่งจะมีผลกับอาร์เรย์ที่คุณสร้าง:

// Somewhere deep in your JavaScript library...
Array.prototype.foo = 1;

// Now you have no idea what the below code will do.
var a = [1, 2, 3, 4, 5];
for (var x in a){
    // Now foo is a part of EVERY array and 
    // will show up here as a value of 'x'.
    console.log(x);
}

/* Will display:
   0
   1
   2
   3
   4
   foo
*/


146
ในอดีตเบราว์เซอร์บางตัวทำซ้ำมากกว่า 'ความยาว', 'toString' ฯลฯ !
s bobinjesu

398
จำไว้ว่าให้ใช้(var x in a)มากกว่า(x in a)- ไม่ต้องการสร้างโลก
Chris Morgan

78
ปัญหาแรกไม่ใช่เหตุผลที่ดี แต่มีความหมายแตกต่างกัน ปัญหาที่สองดูเหมือนว่าฉันมีเหตุผล (ด้านบนของการปะทะกันระหว่างห้องสมุดทำเช่นเดียวกัน) ว่าการเปลี่ยนต้นแบบของชนิดข้อมูลในตัวนั้นไม่ดีแทนที่จะเป็นเพราะในนั้นไม่ดี
สจ๊วต

86
@Stewart: วัตถุทั้งหมดใน JS มีความสัมพันธ์ JS Array เป็นวัตถุดังนั้นใช่มันเชื่อมโยงกันด้วย แต่นั่นไม่ใช่สิ่งที่มันต้องการ หากคุณต้องการที่จะย้ำกว่าวัตถุปุ่มfor (var key in object)การใช้งาน หากคุณต้องการที่จะย้ำกว่าของอาร์เรย์องค์ประกอบfor(var i = 0; i < array.length; i += 1)แต่การใช้งาน
Martijn

42
คุณพูดถึงตัวอย่างแรกว่ามันซ้ำกับดัชนีตัวเลขตั้งแต่ 0 ถึง 4 ตามที่ทุกคนคาดหวังฉันคาดว่ามันจะย้ำตั้งแต่ 0 ถึง 5 ! เนื่องจากถ้าคุณเพิ่มองค์ประกอบในตำแหน่งที่ 5 อาร์เรย์จะมี 6 องค์ประกอบ (5 องค์ประกอบไม่ได้กำหนด)
stivlo

393

for-inคำสั่งด้วยตัวเองไม่ได้เป็น "การปฏิบัติที่ไม่ดี" แต่มันอาจจะผิดพลาดที่ใช้สำหรับตัวอย่างเช่นในการย้ำมากกว่าอาร์เรย์หรืออาร์เรย์เหมือนวัตถุ

วัตถุประสงค์ของfor-inคำสั่งคือเพื่อระบุคุณสมบัติของวัตถุ คำสั่งนี้จะเพิ่มขึ้นในห่วงโซ่ต้นแบบรวมทั้งระบุคุณสมบัติที่สืบทอดมาซึ่งเป็นสิ่งที่บางครั้งไม่ต้องการ

นอกจากนี้ลำดับของการวนซ้ำไม่ได้รับประกันโดย spec. ซึ่งหมายความว่าหากคุณต้องการ "วนซ้ำ" วัตถุอาร์เรย์ด้วยคำสั่งนี้คุณไม่สามารถมั่นใจได้ว่าคุณสมบัติ (ดัชนีอาร์เรย์) จะถูกเยี่ยมชมในลำดับตัวเลข

ตัวอย่างเช่นใน JScript (IE <= 8) ลำดับของการแจกแจงแม้บนอ็อบเจ็กต์ Array จะถูกกำหนดตามคุณสมบัติที่สร้างขึ้น:

var array = [];
array[2] = 'c';
array[1] = 'b';
array[0] = 'a';

for (var p in array) {
  //... p will be "2", "1" and "0" on IE
}

นอกจากนี้การพูดเกี่ยวกับคุณสมบัติที่สืบทอดมาเช่นถ้าคุณขยาย Array.prototypeวัตถุ (เช่นบางไลบรารีเช่น MooTools do) คุณสมบัตินั้นจะถูกนับเช่นกัน:

Array.prototype.last = function () { return this[this.length-1]; };

for (var p in []) { // an empty array
  // last will be enumerated
}

อย่างที่ฉันบอกไปแล้วก่อนที่จะวนซ้ำอาร์เรย์หรือวัตถุที่มีลักษณะคล้ายอาร์เรย์สิ่งที่ดีที่สุดคือการใช้การวนซ้ำตามลำดับเช่นแบบเก่าfor/ whileแบบวนซ้ำ

เมื่อคุณต้องการระบุคุณสมบัติเฉพาะของวัตถุ (วัตถุที่ไม่สืบทอด) คุณสามารถใช้hasOwnPropertyเมธอด:

for (var prop in obj) {
  if (obj.hasOwnProperty(prop)) {
    // prop is not inherited
  }
}

และบางคนแนะนำให้เรียกวิธีการโดยตรงจากObject.prototypeเพื่อหลีกเลี่ยงปัญหาหากมีคนเพิ่มคุณสมบัติที่มีชื่อhasOwnPropertyในวัตถุของเรา:

for (var prop in obj) {
  if (Object.prototype.hasOwnProperty.call(obj, prop)) {
    // prop is not inherited
  }
}

10
ดูโพสต์ของ David Humphrey วนซ้ำวัตถุใน JavaScript อย่างรวดเร็ว - เนื่องจากอาร์เรย์for..inนั้นช้ากว่าลูป "ปกติ" มาก
Chris Morgan

17
คำถามเกี่ยวกับจุดสุดท้ายเกี่ยวกับ "hasOwnProperty": หากมีคนแทนที่ "hasOwnProperty" บนวัตถุคุณจะมีปัญหา แต่คุณจะไม่พบปัญหาเดียวกันหรือเปล่าถ้ามีคนแทนที่ "Object.prototype.hasOwnProperty"? ไม่ว่าพวกเขาจะทำให้คุณแย่ขนาดไหน แต่มันก็ไม่รับผิดชอบ
Scott Rippey

คุณบอกว่าfor..inไม่ใช่การฝึกฝนที่ไม่ดี แต่มันอาจถูกนำไปใช้ในทางที่ผิด คุณมีตัวอย่างการปฏิบัติที่ดีในโลกแห่งความเป็นจริงที่คุณต้องการผ่านคุณสมบัติของวัตถุทั้งหมดรวมถึงคุณสมบัติที่สืบทอดมาหรือไม่?
rjmunro

4
@ScottRippey: ถ้าคุณต้องการที่จะมี: youtube.com/watch?v=FrFUI591WhI
นาธานวอลล์

ด้วยคำตอบนี้ฉันพบว่าสามารถเข้าถึงค่าด้วยfor (var p in array) { array[p]; }
equiman

117

มีเหตุผลสามประการที่คุณไม่ควรใช้for..inย้ำองค์ประกอบของอาร์เรย์:

  • for..inจะวนซ้ำคุณสมบัติของตัวเองและสืบทอดทั้งหมดของวัตถุอาร์เรย์ที่ไม่ได้DontEnum; นั่นหมายความว่าถ้ามีคนเพิ่มคุณสมบัติให้กับวัตถุอาเรย์เฉพาะ (มีเหตุผลที่ถูกต้องสำหรับเรื่องนี้ - ฉันทำเพื่อตัวเอง) หรือเปลี่ยนแปลงArray.prototype(ซึ่งถือว่าเป็นการปฏิบัติที่ไม่ดีในรหัสซึ่งควรทำงานได้ดีกับสคริปต์อื่น ๆ ) คุณสมบัติเหล่านี้จะ จงทำซ้ำเช่นกัน คุณสมบัติที่สืบทอดสามารถแยกออกได้โดยการตรวจสอบhasOwnProperty()แต่นั่นจะไม่ช่วยคุณในการกำหนดคุณสมบัติในวัตถุอาร์เรย์

  • for..in ไม่รับประกันว่าจะรักษาลำดับการสั่งซื้อ

  • มันช้าเพราะคุณต้องเดินคุณสมบัติทั้งหมดของวัตถุอาร์เรย์และห่วงโซ่ต้นแบบทั้งหมดและจะยังคงได้รับชื่อของคุณสมบัติเท่านั้นเช่นการรับค่าการค้นหาเพิ่มเติมจะต้อง


55

เพราะสำหรับ ... ในแจงนับผ่านวัตถุที่เก็บอาร์เรย์ไม่ใช่อาร์เรย์เอง ถ้าฉันเพิ่มฟังก์ชั่นลงในเชนต้นแบบของอาร์เรย์นั่นจะรวมอยู่ด้วย กล่าวคือ

Array.prototype.myOwnFunction = function() { alert(this); }
a = new Array();
a[0] = 'foo';
a[1] = 'bar';
for(x in a){
 document.write(x + ' = ' + a[x]);
}

สิ่งนี้จะเขียน:

0 = foo
1 = แถบ
myOwnFunction = function () {alert (this); }

และเนื่องจากคุณไม่สามารถมั่นใจได้ว่าจะไม่มีการเพิ่มอะไรเข้าไปในห่วงโซ่ต้นแบบเพียงแค่ใช้สำหรับการวนรอบเพื่อระบุอาร์เรย์:

for(i=0,x=a.length;i<x;i++){
 document.write(i + ' = ' + a[i]);
}

สิ่งนี้จะเขียน:

0 = foo
1 = แถบ

16
อาร์เรย์เป็นวัตถุไม่มี "วัตถุที่เก็บอาร์เรย์"
RobG

41

ในการแยกไม่มีอะไรผิดปกติกับการใช้ for-in ในอาร์เรย์ สำหรับในการวนซ้ำชื่อคุณสมบัติของวัตถุและในกรณีของอาร์เรย์ "out-of-the-box" คุณสมบัติจะสอดคล้องกับดัชนีอาร์เรย์ (คุณสมบัติเช่นlengthในตัวtoStringและอื่น ๆ จะไม่รวมอยู่ในการทำซ้ำ)

อย่างไรก็ตามหากรหัสของคุณ (หรือเฟรมเวิร์กที่คุณใช้อยู่) เพิ่มคุณสมบัติที่กำหนดเองให้กับอาร์เรย์หรือไปที่ต้นแบบของอาร์เรย์คุณสมบัติเหล่านี้จะรวมอยู่ในการทำซ้ำซึ่งอาจไม่ใช่สิ่งที่คุณต้องการ

เฟรมเวิร์ก JS บางตัวเช่น Prototype จะแก้ไขต้นแบบ Array กรอบงานอื่น ๆ เช่น JQuery ไม่ได้ดังนั้นด้วย JQuery คุณจึงสามารถใช้งานได้อย่างปลอดภัย

หากคุณมีข้อสงสัยคุณอาจไม่ควรใช้ for-in

อีกทางเลือกหนึ่งในการวนซ้ำผ่านอาร์เรย์คือการใช้ for-loop:

for (var ix=0;ix<arr.length;ix++) alert(ix);

อย่างไรก็ตามนี่มีปัญหาที่แตกต่างกัน ปัญหาคืออาร์เรย์ JavaScript สามารถมี "หลุม" หากคุณกำหนดarrเป็น:

var arr = ["hello"];
arr[100] = "goodbye";

จากนั้นอาร์เรย์มีสองรายการ แต่ความยาวของ 101 ใช้สำหรับในการจะให้ผลผลิตสองดัชนีในขณะที่สำหรับวงจะให้ผลผลิต 101 ดัชนีที่ 99 undefinedมีค่า


37

ตั้งแต่ปี 2559 (ES6) เราอาจใช้for…ofสำหรับการทำซ้ำอาร์เรย์ตามที่ John Slegers สังเกตเห็นแล้ว

ฉันแค่อยากจะเพิ่มรหัสสาธิตอย่างง่าย ๆ เพื่อให้ชัดเจนยิ่งขึ้น:

Array.prototype.foo = 1;
var arr = [];
arr[5] = "xyz";

console.log("for...of:");
var count = 0;
for (var item of arr) {
    console.log(count + ":", item);
    count++;
    }

console.log("for...in:");
count = 0;
for (var item in arr) {
    console.log(count + ":", item);
    count++;
    }

คอนโซลแสดง:

for...of:

0: undefined
1: undefined
2: undefined
3: undefined
4: undefined
5: xyz

for...in:

0: 5
1: foo

ในคำอื่น ๆ :

  • for...ofนับ 0-5 Array.prototype.fooและยังละเว้น มันแสดงให้เห็นอาร์เรย์ค่า

  • for...inรายชื่อเท่านั้น5โดยไม่สนใจดัชนีอาร์เรย์ที่ไม่ได้กำหนด fooแต่เพิ่ม มันแสดงให้เห็นอาร์เรย์ชื่อคุณสมบัติ


32

คำตอบสั้น ๆ : มันไม่คุ้มค่า


คำตอบอีกต่อไป: มันไม่คุ้มค่าแม้ว่าจะไม่ต้องการลำดับองค์ประกอบและประสิทธิภาพที่ดีที่สุด


คำตอบยาว: มันไม่คุ้มค่า ...

  • การใช้for (var property in array)จะทำให้arrayการวนซ้ำเป็นวัตถุการวนซ้ำของวัตถุต้นแบบและการทำงานช้ากว่าการforวนซ้ำแบบอิงดัชนี
  • for (... in ...) ไม่รับประกันว่าจะส่งคืนคุณสมบัติของวัตถุตามลำดับซึ่งอาจเกิดขึ้นได้
  • การใช้hasOwnProperty()และ!isNaN()ตรวจสอบเพื่อกรองคุณสมบัติของวัตถุเป็นค่าใช้จ่ายเพิ่มเติมซึ่งทำให้การทำงานช้าลงและทำให้เหตุผลสำคัญสำหรับการใช้งานในตอนแรกลดลงนั่นคือเนื่องจากรูปแบบที่กระชับยิ่งขึ้น

ด้วยเหตุผลเหล่านี้การแลกเปลี่ยนที่ยอมรับได้ระหว่างประสิทธิภาพและความสะดวกสบายจึงไม่มีอยู่ ไม่มีประโยชน์จริง ๆ เว้นแต่ว่ามีเจตนาที่จะจัดการกับอาร์เรย์เป็นวัตถุและดำเนินการกับคุณสมบัติของวัตถุของอาร์เรย์


31

นอกเหนือจากเหตุผลที่ให้ไว้ในคำตอบอื่น ๆ คุณอาจไม่ต้องการใช้โครงสร้าง "สำหรับ ... ใน" ถ้าคุณต้องการทำคณิตศาสตร์ด้วยตัวแปรตัวนับเนื่องจากการวนซ้ำวนซ้ำผ่านชื่อของคุณสมบัติของวัตถุและตัวแปร เป็นสตริง

ตัวอย่างเช่น,

for (var i=0; i<a.length; i++) {
    document.write(i + ', ' + typeof i + ', ' + i+1);
}

จะเขียน

0, number, 1
1, number, 2
...

ในขณะที่

for (var ii in a) {
    document.write(i + ', ' + typeof i + ', ' + i+1);
}

จะเขียน

0, string, 01
1, string, 11
...

แน่นอนว่าสิ่งนี้สามารถเอาชนะได้โดยรวมถึง

ii = parseInt(ii);

ในลูป แต่โครงสร้างแรกนั้นตรงกว่า


6
คุณสามารถใช้คำนำหน้า+แทนparseIntเว้นแต่คุณจะต้องการจำนวนเต็มจริงหรือละเว้นอักขระที่ไม่ถูกต้อง
Konrad Borowski

นอกจากนี้parseInt()ไม่แนะนำให้ใช้ ลองparseInt("025");และมันจะล้มเหลว
Derek 朕會功夫

6
@Derek朕會功夫- parseIntคุณสามารถใช้แน่นอน ปัญหาคือถ้าคุณไม่ได้ใส่ Radix เบราว์เซอร์รุ่นเก่าอาจพยายามตีความหมายเลข (025 กลายเป็นฐานแปด) สิ่งนี้ได้รับการแก้ไขใน ECMAScript 5 แต่มันยังคงเกิดขึ้นสำหรับตัวเลขที่ขึ้นต้นด้วย "0x" (ซึ่งตีความตัวเลขเป็นเลขฐานสิบหก) เพื่อให้อยู่ในด้านที่ปลอดภัยให้ใช้เลขฐานเพื่อระบุตัวเลขเช่นนั้นparseInt("025", 10)- ซึ่งระบุฐาน 10
IAmTimCorey

23

นอกเหนือจากข้อเท็จจริงที่ว่าfor... inวนรอบคุณสมบัติที่นับได้ทั้งหมด (ซึ่งไม่เหมือนกับ "องค์ประกอบอาร์เรย์ทั้งหมด"!) ดูที่http://www.ecma-international.org/publications/files/ECMA-ST/Ecma -262.pdfส่วนที่ 12.6.4 (ฉบับที่ 5) หรือ 13.7.5.15 (ฉบับที่ 7):

กลไกและลำดับของการแจกแจงคุณสมบัติ ... ไม่ได้ระบุไว้ ...

(ของฉันเน้น)

นั่นหมายความว่าหากเบราว์เซอร์ต้องการมันสามารถผ่านคุณสมบัติตามลำดับที่พวกเขาแทรก หรือในลำดับตัวเลข หรือตามลำดับศัพท์ (โดยที่ "30" มาก่อน "4" โปรดจำไว้ว่าคีย์วัตถุทั้งหมด - และด้วยเหตุนี้ดัชนีอาร์เรย์ทั้งหมด - จึงเป็นสตริงจริง ๆ แล้วทำให้มีเหตุผลทั้งหมด) มันสามารถผ่านไปได้ด้วย bucket ถ้ามันนำ object ไปใช้เป็นตารางแฮช หรือใช้สิ่งใดสิ่งหนึ่งและเพิ่ม "ย้อนกลับ" เบราว์เซอร์อาจทำซ้ำแบบสุ่มและเป็นไปตามมาตรฐาน ECMA-262 ตราบใดที่มันเยี่ยมชมแต่ละสถานที่ให้บริการเพียงครั้งเดียว

ในทางปฏิบัติปัจจุบันเบราว์เซอร์ส่วนใหญ่ต้องการที่จะทำซ้ำในลำดับเดียวกันโดยประมาณ แต่ไม่มีอะไรจะพูดว่าพวกเขาต้องทำ นั่นเป็นการนำไปปฏิบัติโดยเฉพาะและสามารถเปลี่ยนแปลงได้ตลอดเวลาหากพบวิธีอื่นที่มีประสิทธิภาพมากกว่า

ไม่ว่าจะด้วยวิธีใดก็ตามfor... inไม่มีความหมายแฝง หากคุณสนใจสั่งซื้อให้ชัดเจนเกี่ยวกับมันและใช้การforวนรอบปกติกับดัชนี


18

เหตุผลหลักสองประการ:

หนึ่ง

อย่างที่คนอื่นพูดคุณอาจได้รับกุญแจที่ไม่ได้อยู่ในอาเรย์ของคุณหรือที่สืบทอดมาจากต้นแบบ ดังนั้นถ้าสมมุติว่าไลบรารีจะเพิ่มคุณสมบัติให้กับต้นแบบ Array หรือ Object:

Array.prototype.someProperty = true

คุณจะได้รับมันเป็นส่วนหนึ่งของทุกอาร์เรย์:

for(var item in [1,2,3]){
  console.log(item) // will log 1,2,3 but also "someProperty"
}

คุณสามารถแก้ปัญหานี้ด้วยวิธีการ hasOwnProperty:

var ary = [1,2,3];
for(var item in ary){
   if(ary.hasOwnProperty(item)){
      console.log(item) // will log only 1,2,3
   }
}

แต่นี่เป็นความจริงสำหรับวนซ้ำวัตถุใด ๆ ที่มีการวนรอบใน

สอง

โดยปกติแล้วลำดับของรายการในอาเรย์นั้นมีความสำคัญ แต่ลูป for-in ไม่จำเป็นต้องวนซ้ำในลำดับที่ถูกต้องนั่นเป็นเพราะมันถือว่าอาร์เรย์เป็นวัตถุซึ่งเป็นวิธีที่มันถูกนำไปใช้ใน JS และไม่ เป็นอาร์เรย์ ดูเหมือนว่าจะเป็นเรื่องเล็ก ๆ น้อย ๆ แต่จริงๆแล้วมันสามารถทำให้แอพพลิเคชั่นหลุดออกและยากต่อการแก้ไข


2
Object.keys(a).forEach( function(item) { console.log(item) } )วนซ้ำในคีย์คุณสมบัติของตัวเองไม่ใช่จากสิ่งที่สืบทอดมาจากต้นแบบ
Qwerty

2
เป็นจริง แต่เหมือนกับ for-in loop นั้นไม่จำเป็นต้องอยู่ในลำดับดัชนีที่ถูกต้อง นอกจากนี้มันจะไม่ทำงานบนเบราว์เซอร์รุ่นเก่าที่ไม่รองรับ ES5
Lior

คุณสามารถสอนเบราว์เซอร์เหล่านั้นได้array.forEachโดยการแทรกโค้ดบางอย่างลงในสคริปต์ของคุณ ดูนักพัฒนา
Qwerty

แน่นอน แต่จากนั้นคุณกำลังจัดการกับต้นแบบและนั่นไม่ใช่ความคิดที่ดีเสมอไป ... และถึงกระนั้นคุณก็มีปัญหาเรื่องคำสั่ง ...
Lior

และแน่นอนด้วยเหตุผลข้อที่สาม: อาร์เรย์เบาบาง
ที่ดีกว่า

16

เพราะมันระบุผ่านเขตข้อมูลวัตถุไม่ใช่ดัชนี คุณสามารถรับค่าด้วยดัชนี "ความยาว" และฉันสงสัยว่าคุณต้องการสิ่งนี้


ดังนั้นวิธีที่ดีที่สุดในการทำเช่นนั้นคืออะไร?
lYriCAlsSH

3
สำหรับ (var i = 0; i <arr.length; i ++) {}
vava

3
ใน firefox 3 คุณสามารถใช้ arr.forEach หรือ (var [i, v] ใน Iterator (arr)) {} ได้ แต่ไม่สามารถใช้งานได้ใน IE แม้ว่าคุณจะสามารถเขียนวิธี forEach ได้ด้วยตัวเอง
vava

และห้องสมุดทุกแห่งก็มีวิธีการของตัวเองเช่นกัน
vava

5
คำตอบนี้ผิด "ความยาว" จะไม่รวมอยู่ในการทำซ้ำแบบ for-in มันเป็นคุณสมบัติเท่านั้นที่คุณเพิ่มตัวเองซึ่งรวมอยู่
JacquesB

16

ฉันไม่คิดว่าฉันต้องเพิ่มอะไรมากมายเช่น คำตอบอันมีค่าหรือคำตอบของCMSเกี่ยวกับสาเหตุที่for...inควรหลีกเลี่ยงการใช้ในบางกรณี

อย่างไรก็ตามฉันต้องการเพิ่มในเบราว์เซอร์ที่ทันสมัยมีทางเลือกอื่นfor...inที่สามารถใช้ในกรณีที่for...inไม่สามารถใช้งานได้ ทางเลือกนั่นคือfor...of:

for (var item of items) {
    console.log(item);
}

บันทึก :

น่าเสียดายที่ไม่มีรุ่นของ Internet Explorer ที่รองรับfor...of( Edge 12+ทำ) ดังนั้นคุณจะต้องรออีกสักครู่จนกว่าคุณจะสามารถใช้งานได้ในรหัสการผลิตด้านลูกค้าของคุณ อย่างไรก็ตามมันควรจะปลอดภัยที่จะใช้ในโค้ด JS ฝั่งเซิร์ฟเวอร์ของคุณ (ถ้าคุณใช้Node.js )


@georgeawg คุณหมายถึงfor-ofไม่ได้for-inใช่มั้ย?
ᆼᆺᆼ

15

ปัญหาของfor ... in ...- และสิ่งนี้จะกลายเป็นปัญหาเมื่อโปรแกรมเมอร์ไม่เข้าใจภาษาจริงๆ ไม่ใช่ข้อผิดพลาดหรืออะไรเลย - คือมันวนซ้ำทุกสมาชิกของวัตถุ (ดี, สมาชิกที่นับได้ทั้งหมด, แต่นั่นเป็นรายละเอียดสำหรับตอนนี้) เมื่อคุณต้องการย้ำกว่าเพียงคุณสมบัติที่จัดทำดัชนีของอาร์เรย์วิธีรับประกันเฉพาะเพื่อให้สิ่งที่สอดคล้องความหมายคือการใช้ดัชนีจำนวนเต็ม (นั่นคือเป็นfor (var i = 0; i < array.length; ++i)ห่วงรูปแบบ)

วัตถุใด ๆ สามารถมีคุณสมบัติตามอำเภอใจที่เกี่ยวข้อง จะไม่มีอะไรน่ากลัวเกี่ยวกับการโหลดคุณสมบัติเพิ่มเติมลงในอินสแตนซ์ของอาร์เรย์โดยเฉพาะ รหัสที่ต้องการเห็นเฉพาะคุณสมบัติแบบอาเรย์ที่จัดทำดัชนีดังนั้นจะต้องติดอยู่กับดัชนีจำนวนเต็ม รหัสที่ตระหนักถึงสิ่งที่for ... inทำและจำเป็นต้องดูคุณสมบัติทั้งหมดจริง ๆ แล้วก็โอเคด้วย


คำอธิบายที่ดี แค่สงสัย. ถ้าฉันมีอาร์เรย์ที่อยู่ภายในวัตถุภายใต้คุณสมบัติการคูณและfor inเปรียบเทียบกับอาร์เรย์สำหรับลูปปกติแล้วอาร์เรย์เหล่านั้นจะวนซ้ำ (ซึ่งจะเป็นสาระสำคัญประสิทธิภาพช้าใช่มั้ย)
NiCk Newman

2
@NiCkNewman เป็นอย่างดีวัตถุที่คุณอ้างอิงหลังจากinในfor ... inวงจะเพิ่ง
Pointy

ฉันเห็น. เพียงแค่อยากรู้อยากเห็นเพราะฉันมีวัตถุและอาร์เรย์ภายในวัตถุหลักของเกมและสงสัยว่าสำหรับโอกาสที่จะเจ็บปวดมากขึ้นแล้วเพียงแค่ปกติสำหรับการวนรอบดัชนี
NiCk Newman

@NiCkNewman ประเด็นหลักของคำถามนี้คือคุณไม่ควรใช้for ... inอาร์เรย์ มีหลายเหตุผลที่ดีที่ไม่ควรทำ มันไม่มีปัญหาด้านประสิทธิภาพมากนักในฐานะที่เป็น "ทำให้แน่ใจว่าจะไม่เกิดปัญหา"
Pointy

วัตถุของฉันถูกเก็บไว้ในอาร์เรย์ด้วยเหตุนี้ฉันจึงเป็นห่วงฉันชอบอะไร: [{a:'hey',b:'hi'},{a:'hey',b:'hi'}]แต่ใช่ฉันเข้าใจ
NiCk Newman

9

นอกจากนี้เนื่องจากความหมายวิธีfor, inปฏิบัติต่ออาร์เรย์ (เช่นเดียวกับวัตถุ JavaScript อื่น ๆ ) ไม่สอดคล้องกับภาษายอดนิยมอื่น ๆ

// C#
char[] a = new char[] {'A', 'B', 'C'};
foreach (char x in a) System.Console.Write(x); //Output: "ABC"

// Java
char[] a = {'A', 'B', 'C'};
for (char x : a) System.out.print(x);          //Output: "ABC"

// PHP
$a = array('A', 'B', 'C');
foreach ($a as $x) echo $x;                    //Output: "ABC"

// JavaScript
var a = ['A', 'B', 'C'];
for (var x in a) document.write(x);            //Output: "012"

9

TL&DR:การใช้for inลูปในอาร์เรย์นั้นไม่ใช่สิ่งที่เลวร้ายจริงๆแล้วมันค่อนข้างตรงกันข้าม

ฉันคิดว่าfor inloop เป็นอัญมณีของ JS หากใช้อย่างถูกต้องในอาร์เรย์ คุณคาดว่าจะสามารถควบคุมซอฟต์แวร์ของคุณได้อย่างเต็มที่และรู้ว่าคุณกำลังทำอะไรอยู่ เรามาดูข้อเสียดังกล่าวแล้วหักล้างพวกมันทีละคน

  1. มัน loops ผ่านคุณสมบัติได้รับมรดกเช่นกัน:ครั้งแรกของส่วนขยายทั้งหมดใด ๆArray.prototypeควรจะได้รับการดำเนินการโดยใช้Object.defineProperty()ของพวกเขาและให้คำอธิบายควรจะกำหนดให้enumerable falseไม่ควรใช้ไลบรารีใด ๆ ที่ไม่ทำเช่นนี้
  2. คุณสมบัติเหล่านั้นที่คุณเพิ่มในห่วงโซ่การสืบทอดต่อมาได้รับการนับ:เมื่อทำอาร์เรย์ย่อย classing โดยหรือชั้นObject.setPrototypeOf extendอีกครั้งคุณควรใช้Object.defineProperty()ซึ่งโดยชุดเริ่มต้นwritable, enumerableและอธิบายคุณสมบัติการconfigurable falseให้ดูตัวอย่างการแบ่งคลาสย่อยที่นี่ ...

function Stack(...a){
  var stack = new Array(...a);
  Object.setPrototypeOf(stack, Stack.prototype);
  return stack;
}
Stack.prototype = Object.create(Array.prototype);                                 // now stack has full access to array methods.
Object.defineProperty(Stack.prototype,"constructor",{value:Stack});               // now Stack is a proper constructor
Object.defineProperty(Stack.prototype,"peak",{value: function(){                  // add Stack "only" methods to the Stack.prototype.
                                                       return this[this.length-1];
                                                     }
                                             });
var s = new Stack(1,2,3,4,1);
console.log(s.peak());
s[s.length] = 7;
console.log("length:",s.length);
s.push(42);
console.log(JSON.stringify(s));
console.log("length:",s.length);

for(var i in s) console.log(s[i]);

ดังนั้นคุณจะเห็น .. for inลูปนั้นปลอดภัยแล้วเมื่อคุณใส่ใจโค้ดของคุณ

  1. การfor inวนซ้ำช้า:ไม่เลย มันเป็นวิธีที่เร็วที่สุดในการทำซ้ำหากคุณวนลูปอาร์เรย์ที่กระจัดกระจายซึ่งจำเป็นในบางครั้ง นี่เป็นหนึ่งในเทคนิคการปฏิบัติที่สำคัญที่สุดที่ควรรู้ ลองดูตัวอย่าง เราจะวนลูปมากกว่าอาเรย์

var a = [];
a[0] = "zero";
a[10000000] = "ten million";
console.time("for loop on array a:");
for(var i=0; i < a.length; i++) a[i] && console.log(a[i]);
console.timeEnd("for loop on array a:");
console.time("for in loop on array a:");
for(var i in a) a[i] && console.log(a[i]);
console.timeEnd("for in loop on array a:");


@Ravi Shanker Reddy ตั้งค่าการเปรียบเทียบที่ดี ตามที่ฉันได้กล่าวถึงในคำตอบของฉันfor inวนรอบ outshines อื่น ๆ "ถ้า" อาเรย์จะเบาบางและยิ่งถ้ามันได้ขนาดใหญ่ ดังนั้นฉันจึงจัดเรียงการทดสอบแบบตั้งโต๊ะใหม่สำหรับชุดเบาบางarrขนาด ~ 10,000 โดยมีเพียง 50 รายการที่สุ่มเลือก[42,"test",{t:1},null, void 0]จากดัชนีแบบสุ่ม คุณจะสังเกตเห็นความแตกต่างทันที - >> ตรวจสอบได้ที่นี่ << - .
Redu

8

นอกเหนือจากปัญหาอื่น ๆ ไวยากรณ์ "for..in" อาจช้าลงเนื่องจากดัชนีเป็นสตริงไม่ใช่จำนวนเต็ม

var a = ["a"]
for (var i in a)
    alert(typeof i)  // 'string'
for (var i = 0; i < a.length; i++)
    alert(typeof i)  // 'number'

อาจไม่สำคัญมากนัก องค์ประกอบ Array เป็นคุณสมบัติของวัตถุที่ใช้ Array หรือคล้ายกับ Array และคุณสมบัติของวัตถุทั้งหมดมีคีย์สตริง เว้นเสียแต่ว่าเอ็นจิ้น JS ของคุณจะปรับมันอย่างใดแม้ว่าคุณจะใช้ตัวเลขมันก็จะกลายเป็นสตริงสำหรับการค้นหา
cHao

ไม่ว่าปัญหาเรื่องประสิทธิภาพจะเป็นอย่างไรหากคุณยังใหม่กับ JavaScript ให้ใช้var i in aและคาดหวังว่าดัชนีจะเป็นจำนวนเต็มดังนั้นการทำบางสิ่งเช่นa[i+offset] = <value>นี้จะเป็นการใส่ค่าในตำแหน่งที่ผิดอย่างสมบูรณ์ ("1" + 1 == "11")
szmoore

8

สิ่งสำคัญคือการfor...inวนซ้ำคุณสมบัติที่อยู่ในวัตถุที่มีคุณสมบัติคุณสมบัติที่นับ ได้ของพวกเขาตั้งค่าเป็นจริง ดังนั้นหากมีความพยายามที่จะวนซ้ำวัตถุที่ใช้แล้วคุณสมบัติตามอำเภอใจอาจจะพลาดหากคุณสมบัติของคุณสมบัตินับเป็นเท็จ มันค่อนข้างเป็นไปได้ที่จะเปลี่ยนคุณสมบัติของคุณสมบัตินับจำนวนสำหรับวัตถุ Array ปกติเพื่อไม่ให้มีการระบุองค์ประกอบบางอย่าง แม้ว่าโดยทั่วไปแล้วคุณสมบัติของคุณสมบัติมักจะนำไปใช้กับคุณสมบัติของฟังก์ชันภายในวัตถุfor...in

หนึ่งสามารถตรวจสอบค่าของคุณสมบัติคุณสมบัติที่นับได้ของคุณสมบัติโดย:

myobject.propertyIsEnumerable('myproperty')

หรือเพื่อรับคุณสมบัติทั้งสี่:

Object.getOwnPropertyDescriptor(myobject,'myproperty')

นี่เป็นคุณลักษณะที่มีใน ECMAScript 5 - ในเวอร์ชันก่อนหน้านี้ไม่สามารถแก้ไขค่าของคุณสมบัติคุณสมบัติที่นับได้ (มันถูกตั้งค่าเป็นจริงเสมอ)


8

กระบวนการfor/ inทำงานร่วมกับตัวแปรสองประเภท: hashtables (อาเรย์แบบเชื่อมโยง) และอาเรย์ (แบบไม่เชื่อมโยง)

JavaScript จะกำหนดวิธีการส่งผ่านรายการโดยอัตโนมัติ ดังนั้นถ้าคุณรู้ว่าอาเรย์ของคุณไม่มีความเกี่ยวข้องจริงๆคุณสามารถใช้for (var i=0; i<=arrayLen; i++)และข้ามการทำซ้ำการตรวจหาอัตโนมัติ

แต่ในความคิดของฉันดีกว่าที่จะใช้for/ inกระบวนการที่จำเป็นสำหรับการตรวจจับอัตโนมัตินั้นมีขนาดเล็กมาก

คำตอบที่แท้จริงสำหรับสิ่งนี้จะขึ้นอยู่กับวิธีที่เบราว์เซอร์แยกวิเคราะห์ / แปลรหัส JavaScript มันสามารถเปลี่ยนระหว่างเบราว์เซอร์

ฉันไม่สามารถคิดถึงวัตถุประสงค์อื่นที่จะไม่ใช้for/ in;

//Non-associative
var arr = ['a', 'b', 'c'];
for (var i in arr)
   alert(arr[i]);

//Associative
var arr = {
   item1 : 'a',
   item2 : 'b',
   item3 : 'c'
};

for (var i in arr)
   alert(arr[i]);

เป็นจริงเว้นแต่ว่าคุณกำลังใช้วัตถุต้นแบบ ;) ด้านล่าง
Ricardo

Arrayนั่นเป็นเพราะObjectเกินไป
ให้คำปรึกษาฟรี

2
for ... inทำงานกับวัตถุ ไม่มีสิ่งเช่นการตรวจจับอัตโนมัติ
ที่ดีกว่า

7

เพราะมันจะวนซ้ำคุณสมบัติที่เป็นของวัตถุต้นแบบลูกโซ่หากคุณไม่ระวัง

คุณสามารถใช้for.. inเพียงให้แน่ใจว่าการตรวจสอบทรัพย์สินที่มีในแต่ละhasOwnProperty


2
ไม่เพียงพอ - การเพิ่มคุณสมบัติที่มีชื่อตามอำเภอใจให้กับอินสแตนซ์ของอาเรย์นั้นเป็นเรื่องที่ดีพอและสิ่งเหล่านี้จะทดสอบtrueจากการhasOwnProperty()ตรวจสอบ
แหลม

จุดดีขอบคุณ ฉันไม่เคยโง่พอที่จะทำสิ่งนั้นกับ Array ได้ด้วยตัวเองดังนั้นฉันจึงไม่คิดเช่นนั้น!
JAL

1
@ คะแนนฉันยังไม่ได้ทดสอบสิ่งนี้ แต่อาจเอาชนะได้โดยใช้การisNaNตรวจสอบชื่อทรัพย์สินแต่ละรายการ
WynandB

1
@ ความคิดที่น่าสนใจของอินเดีย; แต่ฉันไม่เห็นจริง ๆ ว่าทำไมมันจึงคุ้มค่ากับปัญหาเมื่อทำซ้ำกับดัชนีตัวเลขอย่างง่ายนั้นง่ายมาก
แหลม

@WinnandB ขออภัยสำหรับการชน แต่ฉันรู้สึกว่าการแก้ไขเป็นไปตามลำดับ: isNaNสำหรับการตรวจสอบว่าตัวแปรเป็นค่าพิเศษ NaN หรือไม่มันไม่สามารถใช้ในการตรวจสอบ 'สิ่งอื่น ๆ กว่าตัวเลข' (คุณสามารถไปกับปกติ พิมพ์จากนั้น)
doldt

6

ไม่จำเป็นต้องเลวร้าย (ขึ้นอยู่กับสิ่งที่คุณกำลังทำ) แต่ในกรณีของอาร์เรย์ถ้ามีการเพิ่มบางสิ่งลงไปArray.prototypeคุณจะได้รับผลลัพธ์ที่แปลก ในกรณีที่คุณต้องการให้วงนี้ทำงานสามครั้ง:

var arr = ['a','b','c'];
for (var key in arr) { ... }

หากฟังก์ชั่นที่เรียกว่าhelpfulUtilityMethodได้รับการเพิ่มArray's prototypeแล้วห่วงของคุณจะสิ้นสุดการทำงานครั้งที่สี่: keyจะเป็น0, 1, และ2 helpfulUtilityMethodหากคุณคาดหวังว่าจะเป็นจำนวนเต็มเท่านั้นโอ๊ะโอ


6

คุณควรใช้for(var x in y)รายการทรัพย์สินเท่านั้นไม่ใช่วัตถุ (ตามที่อธิบายไว้ข้างต้น)


13
เพียงแค่ทราบเกี่ยวกับ SO - ไม่มี 'ด้านบน' เนื่องจากความคิดเห็นเปลี่ยนลำดับบนหน้าตลอดเวลา ดังนั้นเราไม่ทราบว่าคุณหมายถึงความคิดเห็นใด เป็นการดีที่จะพูดว่า "ในความคิดเห็นของผู้ x" ด้วยเหตุผลนี้
JAL

@JAL ... หรือเพิ่มลิงก์ไปยังคำตอบ
WynandB

5

การใช้for...inลูปสำหรับอาร์เรย์นั้นไม่ผิด แต่ฉันก็เดาได้ว่าทำไมมีคนบอกคุณว่า:

1. ) มีฟังก์ชั่นการสั่งซื้อที่สูงขึ้นหรือวิธีการที่มีวัตถุประสงค์สำหรับอาร์เรย์ แต่มีฟังก์ชันการทำงานมากขึ้นและไวยากรณ์ลีนที่เรียกว่า 'forEach': Array.prototype.forEach(function(element, index, array) {} );

2. ) อาร์เรย์มีความยาวเสมอ แต่for...inและforEachไม่เรียกใช้ฟังก์ชันสำหรับค่าใด ๆ ที่เป็นค่า'undefined'เฉพาะสำหรับดัชนีที่มีค่าที่กำหนดไว้เท่านั้น ดังนั้นหากคุณกำหนดเพียงหนึ่งค่าลูปเหล่านี้จะเรียกใช้ฟังก์ชันเพียงครั้งเดียว แต่เนื่องจากอาร์เรย์มีการแจกแจงจึงมักจะมีความยาวจนถึงดัชนีสูงสุดที่มีค่าที่กำหนด แต่ความยาวนั้นจะไม่สังเกตเห็นเมื่อใช้สิ่งเหล่านี้ ลูป

3. ) มาตรฐานสำหรับการวนซ้ำจะเรียกใช้ฟังก์ชันหลายครั้งตามที่คุณกำหนดไว้ในพารามิเตอร์และเนื่องจากอาร์เรย์มีหมายเลขแล้วจึงมีความหมายมากกว่าที่จะกำหนดจำนวนครั้งที่คุณต้องการเรียกใช้ฟังก์ชัน ต่างจากลูปอื่น ๆ สำหรับลูปนั้นสามารถเรียกใช้ฟังก์ชั่นสำหรับทุกดัชนีในอาเรย์ไม่ว่าจะมีการกำหนดค่า

ในสาระสำคัญคุณสามารถใช้วงใด ๆ แต่คุณควรจำไว้อย่างชัดเจนว่าพวกเขาทำงานอย่างไร ทำความเข้าใจกับเงื่อนไขที่ลูปที่แตกต่างกันย้ำถึงฟังก์ชั่นที่แยกต่างหากและตระหนักว่าพวกเขาจะเหมาะสมมากขึ้นหรือน้อยลงสำหรับสถานการณ์ที่แตกต่างกัน

นอกจากนี้อาจถือว่าเป็นวิธีปฏิบัติที่ดีกว่าในการใช้forEachวิธีนี้กว่าการfor...inวนซ้ำโดยทั่วไปเนื่องจากง่ายต่อการเขียนและมีฟังก์ชันการทำงานมากขึ้นดังนั้นคุณอาจต้องการใช้วิธีนี้และมาตรฐานสำหรับนิสัยของคุณเท่านั้น โทร.

ดูด้านล่างว่าสองลูปแรกเรียกใช้งานคำสั่ง console.log เพียงครั้งเดียวในขณะที่มาตรฐานสำหรับลูปเรียกใช้ฟังก์ชันหลายครั้งตามที่ระบุในกรณีนี้ array.length = 6

var arr = [];
arr[5] = 'F';

for (var index in arr) {
console.log(index);
console.log(arr[index]);
console.log(arr)
}
// 5
// 'F'
// => (6) [undefined x 5, 6]

arr.forEach(function(element, index, arr) {
console.log(index);
console.log(element);
console.log(arr);
});
// 5
// 'F'
// => Array (6) [undefined x 5, 6]

for (var index = 0; index < arr.length; index++) {
console.log(index);
console.log(arr[index]);
console.log(arr);
};
// 0
// undefined
// => Array (6) [undefined x 5, 6]

// 1
// undefined
// => Array (6) [undefined x 5, 6]

// 2
// undefined
// => Array (6) [undefined x 5, 6]

// 3
// undefined
// => Array (6) [undefined x 5, 6]

// 4
// undefined
// => Array (6) [undefined x 5, 6]

// 5
// 'F'
// => Array (6) [undefined x 5, 6]

4

นี่คือเหตุผลว่าทำไมนี่จึงเป็นแนวปฏิบัติที่ไม่ดี:

  1. for...inวนซ้ำทุกคุณสมบัติที่นับได้ของตัวเองและคุณสมบัติที่นับได้ของต้นแบบ โดยปกติในการทำซ้ำอาร์เรย์เราเพียงต้องการวนซ้ำในอาร์เรย์เท่านั้น และแม้ว่าคุณเองอาจไม่เพิ่มอะไรลงในอาร์เรย์ แต่ไลบรารีหรือกรอบงานของคุณอาจเพิ่มบางสิ่ง

ตัวอย่าง :

Array.prototype.hithere = 'hithere';

var array = [1, 2, 3];
for (let el in array){
    // the hithere property will also be iterated over
    console.log(el);
}

  1. for...inลูปไม่รับประกันการสั่งซื้อซ้ำที่เฉพาะเจาะจง แม้ว่าโดยทั่วไปจะเห็นคำสั่งซื้อในเบราว์เซอร์ที่ทันสมัยที่สุด แต่ก็ยังไม่มีการรับประกัน 100%
  2. for...inลูปไม่สนใจundefinedองค์ประกอบอาเรย์คือองค์ประกอบอาเรย์ที่ยังไม่ได้รับการกำหนด

ตัวอย่าง ::

const arr = []; 
arr[3] = 'foo';   // resize the array to 4
arr[4] = undefined; // add another element with value undefined to it

// iterate over the array, a for loop does show the undefined elements
for (let i = 0; i < arr.length; i++) {
    console.log(arr[i]);
}

console.log('\n');

// for in does ignore the undefined elements
for (let el in arr) {
    console.log(arr[el]);
}


2

สำหรับ ... ในมีประโยชน์เมื่อทำงานกับวัตถุใน JavaScript แต่ไม่ใช่สำหรับ Array แต่เรายังไม่สามารถพูดได้ว่ามันเป็นวิธีที่ผิด แต่ไม่แนะนำให้ดูที่ตัวอย่างด้านล่างนี้โดยใช้สำหรับ ... ในลูป:

let txt = "";
const person = {fname:"Alireza", lname:"Dezfoolian", age:35}; 
for (const x in person) {
    txt += person[x] + " ";
}
console.log(txt); //Alireza Dezfoolian 35 

ตกลงมาทำกับArrayตอนนี้:

let txt = "";
const person = ["Alireza", "Dezfoolian", 35]; 
for (const x in person) {
   txt += person[x] + " ";
}
console.log(txt); //Alireza Dezfoolian 35 

เมื่อคุณเห็นผลลัพธ์เหมือนกัน ...

แต่ลองทำอะไรสักอย่างมาลองทำอะไรบางอย่างกับArray ...

Array.prototype.someoneelse = "someoneelse";

ตอนนี้เราสร้าง Array ใหม่ ();

let txt = "";
const arr = new Array();
arr[0] = 'Alireza';
arr[1] = 'Dezfoolian';
arr[2] = 35;
for(x in arr) {
 txt += arr[x] + " ";
}
console.log(txt); //Alireza Dezfoolian 35 someoneelse

คุณจะเห็นsomeoneelse !!! ... เราจริงบ่วงผ่านวัตถุอาร์เรย์ใหม่ในกรณีนี้!

เพื่อให้เป็นหนึ่งในเหตุผลที่ว่าทำไมเราต้องใช้for..inอย่างรอบคอบ แต่ก็ไม่เสมอกรณี ...


2

A สำหรับ ... ในลูปจะระบุคีย์เสมอ คีย์คุณสมบัติของวัตถุนั้นเป็นสตริงเสมอแม้กระทั่งคุณสมบัติที่มีการจัดทำดัชนีของอาร์เรย์:

var myArray = ['a', 'b', 'c', 'd'];
var total = 0
for (elem in myArray) {
  total += elem
}
console.log(total); // 00123

1

เนื่องจากองค์ประกอบ JavaScript ได้รับการบันทึกเป็นคุณสมบัติวัตถุมาตรฐานจึงไม่แนะนำให้ทำซ้ำผ่านอาร์เรย์ JavaScript ที่ใช้สำหรับ ... ในลูปเนื่องจากองค์ประกอบปกติและคุณสมบัติที่นับได้ทั้งหมดจะแสดงรายการ

จากhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Indexed_collections


0

แม้ว่าจะไม่ได้ตอบคำถามนี้โดยเฉพาะ แต่ฉันจะเพิ่มว่ามีเหตุผลที่ดีมากที่จะไม่ใช้สำหรับ ... ด้วยNodeList(เป็นอย่างใดอย่างหนึ่งจะได้รับจากการquerySelectorAllโทรเนื่องจากไม่เห็นองค์ประกอบที่ส่งคืนเลยแทน วนซ้ำเฉพาะคุณสมบัติ NodeList

ในกรณีผลเดียวฉันได้:

var nodes = document.querySelectorAll(selector);
nodes
 NodeList [a._19eb]
for (node in nodes) {console.log(node)};
VM505:1 0
VM505:1 length
VM505:1 item
VM505:1 entries
VM505:1 forEach
VM505:1 keys
VM505:1 values

ซึ่งอธิบายว่าทำไมฉันถึงfor (node in nodes) node.href = newLink;ล้มเหลว

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.