JavaScript ตีความโดยการออกแบบหรือไม่


73

ฉันระมัดระวังในการถามคำถามนี้เพราะอาจดูเหมือนพิถีพิถันมากเกินไป ฉันเพิ่งเปิด JavaScript: The Definitive Guide และมันระบุไว้ในหน้าแรกของบทที่ 1

"JavaScript เป็นภาษาการเขียนโปรแกรมตีความในระดับสูงแบบไดนามิกและไม่พิมพ์ออกมา"

ดังนั้นฉันจะพูดได้ไหมว่าส่วนที่ตีความนั้นเป็นข้อกำหนดในข้อกำหนดภาษาหรือทำให้เข้าใจผิดว่าภาษานั้นเป็นภาษาโปรแกรมที่ถูกตีความเมื่อเคารพความแตกต่างระหว่างภาษาและการใช้งานหลายอย่าง?

ไม่มีคอมไพเลอร์แบบคงที่สำหรับ JavaScript อย่างชัดเจน - https://stackoverflow.com/questions/1118138/is-there-a-native-machine-code-compiler-for-javascriptดังนั้นอาจเป็นเพียงภาพสะท้อนของสิ่งนี้


มี jscript.net อยู่พักหนึ่งซึ่งคล้ายกับ AS3 / ES4 ที่ "หายไป" มันถูกคอมไพล์ด้วย bytecode ถึง CIL
เฮ้

13
V8 อ้างอย่างชัดเจนว่าไม่ต้องเป็นล่าม แต่เป็นผู้แปล
pimvdb

@GGG JScript.Net ยังมีชีวิตอยู่และ ... อ่อนแอ แต่ยังมีชีวิตอยู่ msdn.microsoft.com/en-us/library/72bd815a.aspx
Jetti

1
FWIW บิต "untyped" ไม่เป็นความจริงอย่างแน่นอนเช่นกัน
Rob Agar

Firefox เพิ่งเปิดตัวคอมไพเลอร์ JIT ที่ใช้เบราว์เซอร์เป็นครั้งแรกในปีนั้นคำถามนั้นได้รับคำตอบใน FF 3.5 ดังนั้นจึงอาจไม่เป็นที่รู้จักอย่างกว้างขวางในเวลานั้น ฉันเชื่อว่า JIT ที่ทันสมัยจริง ๆ แล้วทำการรวบรวมจำนวนมาก (หรืออย่างน้อยเตรียมสำหรับการคอมไพล์) ในรอบแรกของเอกสาร JS เพื่อทำสิ่งต่าง ๆ เช่นการระบุและวิธีแคชที่แยกไปขอบเขตที่กำหนด
Erik Reppen

คำตอบ:


50

ดังนั้นฉันจะพูดได้ไหมว่าส่วนที่ตีความนั้นเป็นข้อกำหนดในข้อกำหนดภาษาหรือทำให้เข้าใจผิดว่าภาษานั้นเป็นภาษาโปรแกรมที่ถูกตีความเมื่อเคารพความแตกต่างระหว่างภาษาและการใช้งานหลายอย่าง?

EcmaScript language geeks มักใช้คำว่า "ES interpreter" เพื่ออ้างถึงการนำ EcmaScript มาใช้ แต่สเป็คไม่ได้ใช้คำนั้น ภาพรวมของภาษาโดยเฉพาะภาษาที่อธิบายในแง่ล่ามไม่เชื่อเรื่องพระเจ้าไปนี้:

ECMAScript เป็นแบบวัตถุ: ภาษาพื้นฐานและเครื่องมืออำนวยความสะดวกสำหรับโฮสต์นั้นจัดทำโดยวัตถุและโปรแกรม ECMAScript เป็นกลุ่มของวัตถุที่ใช้ในการสื่อสาร

ดังนั้น EcmaScript จึงถือว่า "สภาพแวดล้อมของโฮสต์" ซึ่งถูกกำหนดให้เป็นผู้ให้คำจำกัดความของวัตถุรวมถึงสิ่งที่อนุญาตให้ I / O หรือลิงค์อื่น ๆ ไปยังโลกภายนอก แต่ไม่ต้องการล่าม

ความหมายของคำพูดและการแสดงออกในภาษาที่กำหนดไว้ในแง่ของข้อกำหนดเสร็จซึ่งนำมาใช้เล็กน้อยในล่าม แต่ข้อกำหนดไม่ได้ต้องการที่

8.9 ประเภทข้อกำหนดเสร็จสมบูรณ์

ประเภทแล้วเสร็จจะใช้ในการอธิบายพฤติกรรมของงบ ( break, continue, returnและthrow) ที่ดำเนินการถ่ายโอนต่างแดนของการควบคุม ค่าประเภทแล้วเสร็จเป็นอเนกประสงค์ของรูปแบบ ( ชนิด , คุ้มค่า , เป้าหมาย ) ที่ประเภทเป็นหนึ่งในปกติ , ทำลาย , คง , การกลับมาหรือโยน , ค่าใดค่าภาษา ECMAScript หรือที่ว่างเปล่าและเป้าหมายเป็นตัวระบุ ECMAScript ใด ๆ หรือว่างเปล่า

คำว่า“เสร็จสิ้นทันทีทันใด” หมายถึงเสร็จสิ้นการใด ๆ กับประเภทอื่น ๆ กว่าปกติ

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

"EcmaScript Engine"อาจเป็นวิธีที่ดีกว่าในการแสดงแนวคิดเดียวกัน


ไม่มีคอมไพเลอร์สแตติกสำหรับ JavaScript อย่างเห็นได้ชัด

นี่ไม่เป็นความจริง. V8 "ล่าม" รวบรวมรหัสท้องถิ่นภายใน Rhino เลือกที่จะรวบรวม Java bytecode ภายในและล่าม Mozilla ต่างๆ ({Trace, Spider, Jager} Monkey) ใช้คอมไพเลอร์ JIT

V8 :

V8 เพิ่มประสิทธิภาพโดยการรวบรวม JavaScript เป็นรหัสเครื่องก่อนที่จะดำเนินการกับการดำเนินการ bytecode หรือตีความมัน

แรด :

public final void setOptimizationLevel(int optimizationLevel)

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

TraceMonkey :

TraceMonkey เพิ่มการรวบรวมรหัสเนทีฟในเอนจินJavaScript®ของ Mozilla (รู้จักในชื่อ“ SpiderMonkey”) มันขึ้นอยู่กับเทคนิคที่พัฒนาขึ้นที่ UC Irvine ที่เรียกว่า "trace trees" และการสร้างโค้ดและแนวคิดที่แชร์กับโครงการ Tamarin Tracing ผลลัพธ์สุทธิคือความเร็วที่เพิ่มขึ้นอย่างมากทั้งในเบราว์เซอร์ chrome และเนื้อหาของหน้าเว็บ


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

@ me232, คำสั่งเป็นจริงอย่างมากก่อนปี 2008 แรดก่อนวันที่ แต่ไม่ได้เป็นล่ามที่สำคัญและมีเพียงไม่กี่คนที่จะได้โทษ "the Definitive Guide" ในเวลาที่ไม่สนใจ ฉันไม่ได้อ่านหนังสือดังนั้นฉันจึงไม่สามารถให้ความเห็นเกี่ยวกับวิธีการที่ประโยคนั้นมีคุณภาพโดยรวม
Mike Samuel

คำจำกัดความของ "คอมไพเลอร์แบบคงที่" คืออะไร ฉันคิดว่าคำจำกัดความหมายถึงการรวบรวมเกิดขึ้นเพียงครั้งเดียวและคุณจะได้รับถัง (เช่นการเปลี่ยนแปลง) บิตของบิตที่คุณดำเนินการ AFAIK นี่ไม่ใช่การทำงานของเอ็นจิ้น JavaScript นั่นเป็นเหตุผลที่พวกเขามีde-optimizationขั้นตอน กล่าวอีกนัยหนึ่ง JavaScript ถูกรวบรวมโดยเอ็นจินเหล่านี้ แต่ไม่ได้รวบรวมแบบสแตติก
gman

@gman เครื่องกำเนิด bytecode ของ Rhino ทำงานอย่างนั้น
Mike Samuel

AFAIK ไม่ใช่อย่างนั้น แรดสามารถรวมไฟล์ JavaScript อื่น ๆ ซึ่งจะต้องมีการรวบรวมในขณะทำงาน นั่นไม่ใช่ภาวะแทรกซ้อนที่คงที่
gman

20

V8 JavaScript VM ที่ใช้ใน Chrome ไม่มีล่าม แทนมันประกอบด้วยสองคอมไพเลอร์และรวบรวมรหัสได้ทันที คอมไพเลอร์ตัวใดตัวหนึ่งทำงานได้อย่างรวดเร็ว แต่สร้างโค้ดที่ไม่มีประสิทธิภาพส่วนอีกตัวคือคอมไพเลอร์ที่ปรับให้เหมาะสม

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


19

การเกิดขึ้นของคอมไพเลอร์ JIT สำหรับภาษาสคริปต์ทำให้สายระหว่างการคอมไพล์และการตีความไปถึงจุดที่คำถามไม่ได้มีความหมายมากขนาดนั้น มันเป็นเพียงการตีความเมื่อเครื่องยนต์อ่านบรรทัดของรหัสและดำเนินการได้ทันทีหรือไม่ (โดยปกติแล้วเชลล์สคริปต์จะยังคงใช้งานในลักษณะนี้) มันตีความหรือไม่เมื่อเอ็นจิ้นใช้ไฟล์ทั้งหมดรวบรวมไฟล์ให้กับโค้ดไบต์บางส่วนทันทีแล้วตีความโค้ดไบต์? (เอ็นจิ้น Mozilla ขั้นตอนแรกทำงานด้วยวิธีนี้เช่นเดียวกับ CPython) มันตีความหรือไม่เมื่อเอ็นจิ้นวิเคราะห์คำในแต่ละครั้งและ JIT รวบรวมมันเป็นรหัสเนทีฟหรือไม่ สิ่งที่เกี่ยวกับเอ็นจิ้นเหล่านั้นที่รวบรวมไฟล์ทั้งหมดเป็นไบท์โค้ดจากนั้น JIT ทีละฟังก์ชันตามต้องการ (เอ็นจินสคริปต์ส่วนใหญ่วันนี้ทำงานด้วยวิธีนี้

มีหลายเฉดสีระหว่างการรวบรวมและการตีความ

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

แต่ JavaScript ได้รับการออกแบบมาสำหรับการตีความ? ในทางใช่: มันมีevalฟังก์ชั่นเช่นเดียวกับตัวFunctionสร้างที่คุณสามารถให้รหัสโปรแกรมเป็นสตริงซึ่งจะถูกดำเนินการ ความสามารถในการสร้างรหัสโปรแกรมแบบไดนามิก ณ รันไทม์นั้นต้องการเอ็นจิ้นที่สามารถแปลซอร์สโค้ดได้ แต่นี่ไม่ได้หมายความว่าคุณจะไม่สามารถทำทุกอย่างได้ล่วงหน้า แม้ในภาษาที่คอมไพล์เช่น C ++ และ C # คุณสามารถนำซอร์สโค้ดมาคอมไพล์ในหน่วยความจำไปยังรหัสเครื่องใหม่แล้วดำเนินการนั้น มีแม้กระทั่งห้องสมุดที่: LLVM + เสียงดังกราวใน C ++ และโครงการ Roslyn ใน C #

นอกจากนี้กลไกการจัดส่งสำหรับ JavaScript คือซอร์สโค้ด ไม่มีรูปแบบรหัสไบต์ที่รู้จักของมัน C # และ Java มีรหัสไบต์เป็นทางการและทุกคนคาดหวังว่า C ++ จะถูกส่งเป็นรหัสเครื่อง แต่นี่ก็ยังไม่ได้เป็นแง่มุมถ้าภาษาเป็นเพียงสถานการณ์การใช้งานที่โดดเด่น อันที่จริงแล้ว ActionScript ที่สัมพันธ์กันอย่างใกล้ชิดของ JavaScript ใน Flash นั้นได้รับการส่งมอบเป็นรหัสไบต์ (คอมไพเลอร์ Flash จะคอมไพล์สคริปต์ทั้งหมดไว้ล่วงหน้า)


4

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

แต่นี่อาจเป็นคำนิยามที่มีประโยชน์: ภาษาที่แปลแล้วเป็นภาษาที่รันไทม์ภาษามาตรฐานสามารถใช้ข้อความต้นฉบับเป็นอินพุตและดำเนินการได้ โดยนิยาม Perl, Python, Ruby, JavaScript และเชลล์สคริปต์และสิ่งที่คล้ายกันถูกตีความ (แม้ว่าพวกเขาจะใช้ขั้นตอนกลางเช่น bytecode หรือรหัสพื้นเมือง) Java, C #, C ฯลฯ ไม่ใช่ และจาวาสคริปต์ก็ถูกตีความโดยนิยามแม้ว่าสเป็คไม่ได้ใช้คำที่แน่นอน


อืมฉันไม่ชอบให้ Java และ C อยู่ในประเภทเดียวกัน บางทีความแตกต่างที่ดีกว่าคือภาษาที่มีการแจกจ่ายกันมากที่สุดเป็น (A) ซอร์สโค้ด (B) รหัสกลางหรือ (C) รหัสเครื่องจักร ตัวอย่างเช่น A = javascript, B = Java, C = C
John Henckel

การโทรหาภาษาแปลหรือเรียบเรียงไม่ถูกต้อง ยกตัวอย่างเช่นภายใต้กฎนั้นคุณจะเห็นด้วยว่าภาษาซีพลัสพลัสถูกรวบรวมเป็นภาษาใช่ไหม? ถ้าอย่างนั้นเกี่ยวกับ Cling ที่ประมวลผลโค้ด c ++ โดยไม่ต้องคอมไพล์มัน "และสิ่งที่คล้ายกันนั้นถูกตีความ (แม้ว่าพวกเขาจะใช้ขั้นตอนกลางเช่น bytecode หรือรหัสเนทีฟ)" Acc ตามนี้จาวาก็ตีความเช่นกันตีความโดย VM
Abhinav Gauniyal
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.