ลำดับองค์ประกอบในลูป“ สำหรับ (…ใน…)”


205

การวน "for ... in" ใน Javascript วนซ้ำผ่าน hashtables / องค์ประกอบตามลำดับที่ประกาศหรือไม่ มีเบราว์เซอร์ที่ไม่ทำงานตามลำดับหรือไม่
วัตถุที่ฉันต้องการใช้จะถูกประกาศหนึ่งครั้งและจะไม่ถูกแก้ไข

สมมติว่าฉันมี:

var myObject = { A: "Hello", B: "World" };

และฉันก็ใช้มันใน:

for (var item in myObject) alert(item + " : " + myObject[item]);

ฉันสามารถคาดหวังว่า 'A: "Hello"' จะมาก่อน 'B: "World"' ในเบราว์เซอร์ที่ดีที่สุดได้หรือไม่?


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

6
ฉันสงสัยว่าความสามารถจาวาสคริปต์ที่ จำกัด ของตัวเองจะดีกว่าฝูงชน SO นอกจากนี้ใครจะรู้ว่ามีเบราว์เซอร์แปลก ๆ แฝงตัวอยู่ที่นั่น? และคุณสามารถเห็นคำตอบที่ GChrome มีข้อผิดพลาดซึ่งจะไม่ปรากฏในกรณีตัวอย่างง่ายๆของฉัน
chakrit


คำตอบ:


214

จอห์น Resig :

ปัจจุบันเบราว์เซอร์หลักทั้งหมดวนรอบคุณสมบัติของวัตถุตามลำดับที่กำหนดไว้ Chrome ทำได้เช่นกันยกเว้นในบางกรณี [... ] ลักษณะการทำงานนี้ไม่ได้ระบุไว้อย่างชัดเจนโดยข้อกำหนด ECMAScript ใน ECMA-262, ส่วน 12.6.4:

กลไกของการแจกแจงคุณสมบัติ ... ขึ้นอยู่กับการนำไปใช้

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

เบราว์เซอร์ทั้งหมดปฏิบัติตามคำจำกัดความของคำสั่งยกเว้น Chromeและ Opera ที่ใช้กับชื่อคุณสมบัติที่ไม่ใช่ตัวเลขทุกตัว ในเบราว์เซอร์ทั้งสองนี้คุณสมบัติจะถูกดึงตามลำดับล่วงหน้าของคุณสมบัติที่ไม่ใช่ตัวเลขตัวแรก (ซึ่งเกี่ยวข้องกับวิธีการนำอาร์เรย์ไปใช้) คำสั่งซื้อเหมือนกันสำหรับObject.keysเช่นกัน

ตัวอย่างนี้ควรทำให้ชัดเจนว่าเกิดอะไรขึ้น:

var obj = {
  "first":"first",
  "2":"2",
  "34":"34",
  "1":"1",
  "second":"second"
};
for (var i in obj) { console.log(i); };
// Order listed:
// "1"
// "2"
// "34"
// "first"
// "second"

Technicalities ของสิ่งนี้มีความสำคัญน้อยกว่าความจริงที่ว่านี้อาจเปลี่ยนแปลงได้ตลอดเวลา อย่าพึ่งพาสิ่งที่อยู่ในลักษณะนี้

ในระยะสั้น: ใช้อาร์เรย์ถ้าคำสั่งมีความสำคัญต่อคุณ


3
ไม่ได้จริงๆ Chrome ไม่ได้ดำเนินการตามคำสั่งเดียวกับเบราว์เซอร์อื่น ๆ : code.google.com/p/v8/issues/detail?id=164
Tim Down

19
"ใช้อาร์เรย์หากคำสั่งมีความสำคัญต่อคุณ": แล้วเมื่อใช้ JSON ล่ะ
HM2K

11
@ HM2K สิ่งเดียวกันสเปคบอกว่า "วัตถุคือชุดของชื่อ / ค่าคู่ที่ไม่มีการเรียงลำดับ JSON ไม่ใช่ JavaScript: เซิร์ฟเวอร์ไม่จำเป็นต้อง (และอาจจะไม่) ปฏิบัติตามคำสั่งของคุณ
Borgar

7
Firefox ตั้งแต่รุ่น 21 ดูเหมือนจะไม่เคารพคำสั่งแทรกอีกต่อไป
Doc Davluz

2
คำตอบนี้เป็นเท็จใน ES2015
Benjamin Gruenbaum

54

กระแทกในอีกหนึ่งปีต่อมา ...

มันคือ2012และเบราว์เซอร์หลักยังคงแตกต่างกัน:

function lineate(obj){
    var arr = [], i;
    for (i in obj) arr.push([i,obj[i]].join(':'));
    console.log(arr);
}
var obj = { a:1, b:2, c:3, "123":'xyz' };
/* log1 */  lineate(obj);
obj.a = 4;
/* log2 */  lineate(obj);
delete obj.a;
obj.a = 4;
/* log3 */  lineate(obj);

สรุปสาระสำคัญหรือทดสอบในเบราว์เซอร์ปัจจุบัน

Safari 5, Firefox 14

["a:1", "b:2", "c:3", "123:xyz"]
["a:4", "b:2", "c:3", "123:xyz"]
["b:2", "c:3", "123:xyz", "a:4"]

Chrome 21, Opera 12, Node 0.6, Firefox 27

["123:xyz", "a:1", "b:2", "c:3"]
["123:xyz", "a:4", "b:2", "c:3"]
["123:xyz", "b:2", "c:3", "a:4"]

IE9

[123:xyz,a:1,b:2,c:3] 
[123:xyz,a:4,b:2,c:3] 
[123:xyz,a:4,b:2,c:3] 

16
ปัญหานี่คืออะไร ตรงตามที่ระบุไว้ว่าเป็นรายการที่ไม่มีการเรียงลำดับของคู่คีย์ / val
nickf

5
nickf: การติดตั้งใช้งานที่ถูกต้องในสิ่งที่ spec ระบุไว้ ฉันคิดว่าทุกคนยอมรับว่าข้อกำหนดจาวาสคริปต์คือ .. ดีฉันไม่ต้องการใช้คำว่า "ผิด" วิธีการเกี่ยวกับ "โง่มากและน่ารำคาญ"? : P
วางขาย

10
@boxed: คิดว่าวัตถุเป็นแผนที่แฮช (ตาราง / อะไรก็ตาม) ในภาษาส่วนใหญ่ (Java, Python, ฯลฯ ) โครงสร้างข้อมูลประเภทนี้จะไม่ถูกจัดเรียง ดังนั้นจึงไม่น่าแปลกใจที่นี่เป็นกรณีเดียวกันใน JavaScript เช่นกันและแน่นอนว่าจะไม่ทำให้ข้อกำหนดที่ไม่ถูกต้องหรือโง่
เฟลิกซ์คลิง

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

2
ในการนำไปใช้งานที่ทันสมัยคุณจะได้รับคุณสมบัติจำนวนเต็มตามลำดับตัวเลขเนื่องจากการสำรองข้อมูลโดยอาร์เรย์จริงและคุณสมบัติที่มีชื่อจะได้รับตามลำดับการแทรกเนื่องจากการกำหนดคลาส / รูปร่างที่ซ่อนอยู่ สิ่งที่สามารถแตกต่างกันคือไม่ว่าจะเป็นรายการคุณสมบัติจำนวนเต็มก่อนหรือคุณสมบัติที่มีชื่อก่อน การเพิ่มที่deleteน่าสนใจเพราะอย่างน้อยใน V8 มันทำให้วัตถุถูกสำรองโดยตารางแฮชในทันที อย่างไรก็ตามตารางแฮชใน V8 เก็บตามลำดับการแทรก ผลที่น่าสนใจที่สุดที่นี่เป็น IE ผมสงสัยว่าสิ่งที่ชนิดของความน่ากลัวที่พวกเขาทำจะดึงออกว่า ...
Esailija

27

จากข้อกำหนดคุณสมบัติภาษา ECMAScriptส่วน 12.6.4 (บนfor .. inลูป):

กลไกของการแจกแจงคุณสมบัตินั้นขึ้นอยู่กับการนำไปใช้งาน ลำดับของการแจงนับถูกกำหนดโดยวัตถุ

และส่วนที่ 4.3.3 (คำจำกัดความของ "วัตถุ"):

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

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

หากคุณต้องการกำหนดคำสั่งซื้อของคุณคุณจะต้องใช้สิ่งที่กำหนดเช่นอาร์เรย์ของคีย์ที่คุณเรียงลำดับก่อนที่จะเข้าถึงวัตถุด้วย


10

องค์ประกอบของวัตถุที่สำหรับ / ในการระบุเป็นคุณสมบัติที่ไม่มีการตั้งค่าสถานะ DontEnum มาตรฐาน ECMAScript หรือที่รู้จักกันใน Javascript กล่าวอย่างชัดเจนว่า "วัตถุคือชุดของคุณสมบัติที่ไม่มีการเรียงลำดับ" (ดูhttp://www.mozilla.org/js/language/E262-3.pdfส่วน 8.6)

มันจะไม่เป็นไปตามมาตรฐาน (เช่นปลอดภัย) ที่จะถือว่าการใช้งานจาวาสคริปต์ทั้งหมดจะแจกแจงตามลำดับการประกาศ


2
ซึ่งเป็นสาเหตุที่เขาถามคำถามแทนที่จะคิดเพียง: p
Jamie Pate

4

ลำดับการวนซ้ำยังสับสนเกี่ยวกับการลบคุณสมบัติ แต่ในกรณีนี้กับ IE เท่านั้น

var obj = {};
obj.a = 'a';
obj.b = 'b';
obj.c = 'c';

// IE allows the value to be deleted...
delete obj.b;

// ...but remembers the old position if it is added back later
obj.b = 'bb';
for (var p in obj) {
    alert(obj[p]); // in IE, will be a, bb, then c;
                   // not a, c, then bb as for FF/Chrome/Opera/Safari
}

ความปรารถนาสำหรับการเปลี่ยนสเปคในการแก้ไขปัญหาการสั่งซื้อซ้ำดูเหมือนว่าจะค่อนข้างมีความปรารถนาที่เป็นที่นิยมในหมู่นักพัฒนาหากการอภิปรายที่http://code.google.com/p/v8/issues/detail?id=164บ่งชี้ใด ๆ


3

ใน IE6 ไม่รับประกันการสั่งซื้อ


2

คำสั่งซื้อไม่สามารถเชื่อถือได้ ทั้ง Opera และ Chrome จะส่งคืนรายการคุณสมบัติที่ไม่ได้เรียงลำดับ

<script type="text/javascript">
var username = {"14719":"A","648":"B","15185":"C"};

for (var i in username) {
  window.alert(i + ' => ' + username[i]);
}
</script>

รหัสด้านบนแสดง B, A, C ใน Opera และ C, A, B ใน Chrome


1

สิ่งนี้ไม่ได้ตอบคำถามต่อ se แต่เสนอวิธีแก้ปัญหาพื้นฐาน

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

var myArray = [
    {
        'key'   : 'key1'
        'value' : 0
    },
    {
        'key'   : 'key2',
        'value' : 1
    } // ...
];

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

> console.log(myArray[0].key);
key1

> for (let index in myArray) {console.log(myArray[index].value);}
0
1
ดูปากกาสำหรับ ( ... ใน ... ) ที่อยู่ในการสั่งซื้อโดย JDQ ( @JDQ ) บนCodePen

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