เหตุใดบรรทัดนี้จึงถูกต้องในจาวาสคริปต์
var a = 0[0];
หลังจากนั้นaคือundefined.
"0"ของnew Number(0)วัตถุ
0[0]ส่งคืนค่า
0["toString"]เยี่ยมมากขอบคุณที่ชี้ให้ดู
เหตุใดบรรทัดนี้จึงถูกต้องในจาวาสคริปต์
var a = 0[0];
หลังจากนั้นaคือundefined.
"0"ของnew Number(0)วัตถุ
0[0]ส่งคืนค่า
0["toString"]เยี่ยมมากขอบคุณที่ชี้ให้ดู
คำตอบ:
เมื่อคุณทำ0[0], ล่าม JS จะเปิดคนแรกที่0เป็นNumberวัตถุแล้วพยายามเข้าถึงคุณสมบัติของวัตถุที่มีอยู่[0]undefined
ไม่มีข้อผิดพลาดทางไวยากรณ์เนื่องจากไวยากรณ์การเข้าถึงคุณสมบัติ0[0]ได้รับอนุญาตโดยไวยากรณ์ภาษาในบริบทนี้ โครงสร้างนี้ (โดยใช้ข้อตกลงในไวยากรณ์ Javascript) NumericLiteral[NumericLiteral]เป็น
ส่วนที่เกี่ยวข้องของไวยากรณ์ภาษาจากส่วน A.3ของข้อกำหนด ES5 ECMAScript คือ:
Literal ::
NullLiteral
BooleanLiteral
NumericLiteral
StringLiteral
RegularExpressionLiteral
PrimaryExpression :
this
Identifier
Literal
ArrayLiteral
ObjectLiteral
( Expression )
MemberExpression :
PrimaryExpression
FunctionExpression
MemberExpression [ Expression ]
MemberExpression . IdentifierName
new MemberExpression Arguments
ดังนั้นเราสามารถติดตามตัวแกรมมาร์ผ่านความก้าวหน้านี้:
MemberExpression [ Expression ]
PrimaryExpression [ Expression ]
Literal [ Expression ]
NumericLiteral [ Expression ]
และในExpressionที่สุดก็สามารถเป็นNumericLiteralเช่นนั้นได้เช่นกันหลังจากทำตามไวยากรณ์แล้วเราจะเห็นว่าสิ่งนี้ได้รับอนุญาต:
NumericLiteral [ NumericLiteral ]
ซึ่งหมายความว่า0[0]เป็นส่วนที่อนุญาตของไวยากรณ์จึงไม่มี SyntaxError
จากนั้นในขณะรันไทม์คุณจะได้รับอนุญาตให้อ่านคุณสมบัติที่ไม่มีอยู่ (มันจะถูกอ่านเป็นundefined) ตราบเท่าที่แหล่งที่มาที่คุณกำลังอ่านอยู่เป็นวัตถุหรือมีการแปลงโดยนัยเป็นวัตถุ และลิเทอรัลตัวเลขจะมีการแปลงโดยปริยายเป็นอ็อบเจกต์ (อ็อบเจ็กต์ Number)
นี่เป็นหนึ่งในคุณสมบัติของ Javascript ที่มักไม่รู้จัก ประเภทNumber, BooleanและStringใน Javascript จะถูกเก็บไว้ภายในเป็นพื้นฐาน (ไม่ใช่วัตถุเต็มเป่า) สิ่งเหล่านี้เป็นการแสดงพื้นที่จัดเก็บที่กะทัดรัดและไม่เปลี่ยนรูป (อาจทำได้ด้วยวิธีนี้เพื่อประสิทธิภาพในการนำไปใช้งาน) แต่ Javascript ต้องการให้คุณสามารถปฏิบัติกับวัตถุดั้งเดิมเหล่านี้ได้เช่นเดียวกับวัตถุที่มีคุณสมบัติและวิธีการ ดังนั้นหากคุณพยายามเข้าถึงคุณสมบัติหรือวิธีการที่ไม่ได้รับการสนับสนุนโดยตรงบนดั้งเดิม Javascript จะบังคับให้วัตถุดั้งเดิมเป็นประเภทของออบเจ็กต์ที่เหมาะสมชั่วคราวโดยกำหนดค่าเป็นค่าดั้งเดิม
เมื่อคุณใช้ไวยากรณ์ที่เหมือนวัตถุบนพื้นฐานเช่น0[0]ล่ามจะรับรู้ว่าสิ่งนี้เป็นการเข้าถึงคุณสมบัติบนพื้นฐาน การตอบสนองต่อสิ่งนี้คือการใช้0ตัวเลขตัวแรกและบีบบังคับให้กลายเป็นNumberวัตถุที่เต็มไปด้วยวัตถุระเบิดซึ่งจะสามารถเข้าถึง[0]คุณสมบัติได้ ในกรณีนี้โดยเฉพาะที่[0]สถานที่ให้บริการบนวัตถุจำนวนเป็นซึ่งเป็นเหตุผลที่ว่าค่าที่คุณได้รับจากundefined0[0]
นี่คือบทความเกี่ยวกับการแปลงวัตถุดั้งเดิมเป็นวัตถุโดยอัตโนมัติเพื่อวัตถุประสงค์ในการจัดการกับคุณสมบัติ:
ชีวิตลับของ Javascript Primitives
นี่คือส่วนที่เกี่ยวข้องของข้อกำหนด ECMAScript 5.1:
พ่น TypeError ถ้าค่าเป็นundefinedหรือมิฉะนั้นผลตอบแทนnulltrue

- ให้ baseReference เป็นผลลัพธ์ของการประเมิน MemberExpression
- ให้ baseValue เป็น GetValue (baseReference)
- ให้ propertyNameReference เป็นผลลัพธ์ของการประเมิน Expression
- ให้ propertyNameValue เป็น GetValue (propertyNameReference)
- เรียก CheckObjectCoercible (baseValue)
- ให้ propertyNameString เป็น ToString (propertyNameValue)
- หากการผลิตทางวากยสัมพันธ์ที่กำลังประเมินอยู่ในโค้ดโหมดที่เข้มงวดให้เข้มงวดเป็นจริงมิฉะนั้นให้เข้มงวดเป็นเท็จ
- ส่งคืนค่าของชนิด Reference ที่มีค่าพื้นฐานเป็น baseValue และมีชื่อที่อ้างอิงคือ propertyNameString และมีแฟล็กโหมดเข้มงวดเข้มงวด
ส่วนการดำเนินการสำหรับคำถามนี้คือขั้นตอน # 5 ข้างต้น
สิ่งนี้อธิบายถึงวิธีการที่ค่าที่เข้าถึงเป็นการอ้างอิงคุณสมบัติจะเรียกToObject(base)รับเวอร์ชันอ็อบเจ็กต์ของดั้งเดิม
นี้อธิบายวิธีBoolean, NumberและStringวิทยาการจะถูกแปลงเป็นรูปแบบวัตถุกับ [[PrimitiveValue]] ชุดคุณสมบัติภายในตาม
เป็นการทดสอบที่น่าสนใจหากโค้ดเป็นเช่นนี้:
var x = null;
var a = x[0];
มันจะยังคงไม่โยน SyntaxError ในเวลาแยกวิเคราะห์เนื่องจากเป็นไวยากรณ์ทางเทคนิคทางเทคนิค แต่จะส่ง TypeError ที่รันไทม์เมื่อคุณเรียกใช้รหัสเนื่องจากเมื่อตรรกะของ Property Accessors ข้างต้นถูกนำไปใช้กับค่าของxมันจะเรียกCheckObjectCoercible(x)หรือเรียกToObject(x)สิ่งที่ ทั้งสองจะโยน TypeError ถ้าxเป็นหรือnullundefined
0[1,2]ก็ใช้ได้หมายความว่าอย่างไร? (ฉันอัปเดตคำถาม)
nullหรือไม่undefinedดีทั้งหมดแม้ว่าคุณสมบัติเหล่านั้นจะไม่มีอยู่ก็ตาม
0[2]
1,2แต่ส่งกลับ 2
เช่นเดียวกับภาษาโปรแกรมส่วนใหญ่ JS ใช้ไวยากรณ์เพื่อแยกวิเคราะห์รหัสของคุณและแปลงเป็นรูปแบบปฏิบัติการ หากไม่มีกฎในไวยากรณ์ที่สามารถนำไปใช้กับโค้ดบางส่วนได้ก็จะพ่น SyntaxError มิฉะนั้นรหัสจะถือว่าถูกต้องไม่ว่าจะสมเหตุสมผลหรือไม่ก็ตาม
ส่วนที่เกี่ยวข้องของไวยากรณ์ JSคือ
Literal ::
NumericLiteral
...
PrimaryExpression :
Literal
...
MemberExpression :
PrimaryExpression
MemberExpression [ Expression ]
...
เนื่องจาก0[0]เป็นไปตามกฎเหล่านี้จึงถือว่าเป็นนิพจน์ที่ถูกต้อง ไม่ว่าจะถูกต้องหรือไม่ (เช่นไม่ทำให้เกิดข้อผิดพลาดขณะทำงาน) เป็นอีกเรื่องหนึ่ง แต่ใช่ นี่คือวิธีที่ JS ประเมินนิพจน์เช่นsomeLiteral[someExpression]:
someExpression(ซึ่งอาจซับซ้อนโดยพลการ)Number, สตริง => Stringฯลฯ )get propertyดำเนินการกับผลลัพธ์ (2) ด้วยผลลัพธ์ชื่อคุณสมบัติ (1)ดังนั้นจึง0[0]ถูกตีความว่า
index = 0
temp = Number(0)
result = getproperty(temp, index) // it's undefined, but JS doesn't care
delete temp
return result
นี่คือตัวอย่างของความถูกต้องแต่ไม่ถูกต้องแสดงออก:
null[0]
แยกวิเคราะห์ได้ดี แต่ในขณะดำเนินการล่ามจะล้มเหลวในขั้นตอนที่ 2 (เนื่องจากnullไม่สามารถแปลงเป็นวัตถุได้) และแสดงข้อผิดพลาดขณะทำงาน
var x = null; var a = x[0];ไม่สร้างข้อผิดพลาดทางไวยากรณ์ แต่จะส่ง TypeError ที่รันไทม์
0[0]จะส่งคืนค่าแทนการไม่ได้กำหนด
มีสถานการณ์ที่คุณสามารถห้อยตัวเลขใน Javascript ได้อย่างถูกต้อง:
-> 0['toString']
function toString() { [native code] }
แม้ว่าจะไม่ชัดเจนในทันทีว่าทำไมคุณถึงต้องการทำสิ่งนี้การสมัครสมาชิกใน Javascript จะเทียบเท่ากับการใช้สัญกรณ์แบบจุด (แม้ว่าสัญกรณ์จุดจะ จำกัด ให้คุณใช้ตัวระบุเป็นคีย์)
(0).toString(โดยไม่เรียกใช้ฟังก์ชัน) เป็นคุณสมบัติของประเภทตัวเลข
0คุณสมบัติจึงถูกเข้าถึงและเนื่องจากไม่มีอยู่จริงundefinedจึงถูกต้องกว่าตามที่อธิบายไว้ใน jfriend00
0[0]จะกลับมาไม่ได้กำหนด มีแนวโน้มว่าจะเป็นไปได้ แต่ไม่จำเป็นต้องเป็นเช่นนั้น
ฉันแค่อยากจะทราบว่าไวยากรณ์ที่ถูกต้องนี้ไม่ได้ใช้เฉพาะกับ Javascript แต่อย่างใด ภาษาส่วนใหญ่จะมีข้อผิดพลาดรันไทม์หรือข้อผิดพลาดประเภท แต่นั่นไม่ใช่สิ่งเดียวกับข้อผิดพลาดทางไวยากรณ์ Javascript เลือกที่จะส่งคืนที่ไม่ได้กำหนดไว้ในหลาย ๆ สถานการณ์ที่ภาษาอื่นอาจเพิ่มข้อยกเว้นรวมถึงเมื่อการสมัครสมาชิกอ็อบเจ็กต์ที่ไม่มีคุณสมบัติของชื่อที่กำหนด
ไวยากรณ์ไม่ทราบประเภทของนิพจน์ (แม้แต่นิพจน์ธรรมดาเช่นลิเทอรัลตัวเลข) และจะช่วยให้คุณสามารถใช้โอเปอเรเตอร์กับนิพจน์ใดก็ได้ ตัวอย่างเช่นพยายามที่จะห้อยundefinedหรือnullทำให้เกิดTypeErrorใน Javascript ไม่ใช่ข้อผิดพลาดทางไวยากรณ์ - หากสิ่งนี้ไม่เคยดำเนินการ (อยู่ผิดด้านของ if-statement) จะไม่ทำให้เกิดปัญหาใด ๆ ในขณะที่ข้อผิดพลาดทางไวยากรณ์เกิดจากคำจำกัดความที่จับได้ในเวลาคอมไพล์เสมอ (eval, Function ฯลฯ ทั้งหมดนับเป็นการรวบรวม)
เนื่องจากเป็นไวยากรณ์ที่ถูกต้องและแม้แต่รหัสที่ถูกต้องในการตีความ คุณสามารถพยายามเข้าถึงคุณสมบัติของวัตถุใด ๆ (และในกรณีนี้ 0 จะถูกส่งไปยังวัตถุที่เป็นตัวเลข) และจะให้ค่าแก่คุณหากมีอยู่หรือไม่ได้กำหนดไว้ อย่างไรก็ตามการพยายามเข้าถึงคุณสมบัติของ undefined ไม่ได้ผลดังนั้น 0 [0] [0] จะทำให้เกิดข้อผิดพลาดรันไทม์ สิ่งนี้จะยังคงจัดเป็นไวยากรณ์ที่ถูกต้องแม้ว่า มีความแตกต่างของไวยากรณ์ที่ถูกต้องและสิ่งที่จะไม่ทำให้เกิดข้อผิดพลาด runtime / compiletime
ไวยากรณ์ไม่เพียง แต่ถูกต้อง แต่ผลลัพธ์ก็ไม่จำเป็นต้องเป็นไปตามนั้นundefinedส่วนใหญ่ถ้าไม่ใช่ทุกกรณีที่มีเหตุผล JS เป็นหนึ่งในภาษาเชิงวัตถุที่บริสุทธิ์ที่สุด ภาษาที่เรียกว่า OO ส่วนใหญ่จะเน้นคลาสในแง่ที่คุณไม่สามารถเปลี่ยนรูปแบบ (ซึ่งเชื่อมโยงกับคลาส) ของอ็อบเจ็กต์ที่สร้างขึ้นเมื่อสร้างขึ้นแล้วมีเพียงสถานะของอ็อบเจ็กต์เท่านั้น ใน JS คุณสามารถเปลี่ยนสถานะตลอดจนรูปแบบของวัตถุได้ซึ่งคุณทำได้บ่อยกว่าที่คุณคิด ความสามารถนี้ทำให้โค้ดบางส่วนค่อนข้างคลุมเครือหากคุณใช้ผิด ตัวเลขไม่เปลี่ยนรูปดังนั้นคุณจึงไม่สามารถเปลี่ยนวัตถุเองได้ไม่ใช่สถานะหรือรูปแบบดังนั้นคุณจึงสามารถทำได้
0[0] = 1;
ซึ่งเป็นนิพจน์การกำหนดที่ถูกต้องซึ่งส่งคืน 1 แต่ไม่ได้กำหนดอะไรเลยจริง ๆ แล้วตัวเลข0ไม่เปลี่ยนรูป ซึ่งในตัวมันค่อนข้างแปลก คุณสามารถมีนิพจน์การกำหนด (ปฏิบัติการ) ที่ถูกต้องและถูกต้องซึ่งไม่ได้กำหนดอะไรเลย (*) อย่างไรก็ตามประเภทของตัวเลขเป็นวัตถุที่ไม่แน่นอนดังนั้นคุณจึงสามารถกลายพันธุ์ประเภทได้และการเปลี่ยนแปลงจะลดหลั่นกันไปตามห่วงโซ่ต้นแบบ
Number[0] = 1;
//print 1 to the console
console.log(0[0]);
//will also print 1 to the console because all integers have the same type
console.log(1[0]);
แน่นอนว่ามันเป็นวิธีที่ห่างไกลจากหมวดหมู่การใช้งานที่มีเหตุผล แต่มีการระบุภาษาที่อนุญาตให้ทำเช่นนี้ได้เพราะในสถานการณ์อื่น ๆ การขยายความสามารถของวัตถุนั้นสมเหตุสมผลมาก เป็นวิธีที่ปลั๊กอิน jQuery เชื่อมต่อกับวัตถุ jQuery เพื่อให้เป็นตัวอย่าง
(*) จริง ๆ แล้วมันกำหนดค่า 1 ให้กับคุณสมบัติของวัตถุอย่างไรก็ตามไม่มีทางที่คุณสามารถอ้างอิงวัตถุนั้น (ชั่วคราว) ได้และจะถูกรวบรวมที่ nexx GC pass
ใน JavaScript ทุกอย่างเป็นวัตถุดังนั้นเมื่อล่ามแยกวิเคราะห์มันจะถือว่า 0 เป็นวัตถุและพยายามส่งคืน 0 เป็นคุณสมบัติ สิ่งเดียวกันนี้เกิดขึ้นเมื่อคุณพยายามเข้าถึงองค์ประกอบที่ 0 ของ true หรือ "" (สตริงว่าง)
แม้ว่าคุณจะตั้งค่า 0 [0] = 1 มันจะตั้งค่าคุณสมบัติและค่าของมันในหน่วยความจำ แต่ในขณะที่คุณเข้าถึง 0 มันจะถือว่าเป็นตัวเลข (อย่าสับสนระหว่างการปฏิบัติเป็น Object และตัวเลขที่นี่)
true[0]หรือ""[0]