เกิดอะไรขึ้นกับการรวม
ข้อเสนอสำหรับฟีเจอร์ภาษา JavaScript ที่ชื่อ Array.prototype.flatten
ใช้งานร่วมกับเว็บไม่ได้ การนำฟีเจอร์นี้มาใช้ใน Firefox Nightly ทำให้เว็บไซต์ยอดนิยมอย่างน้อย 1 เว็บไซต์ใช้งานไม่ได้ เนื่องจากโค้ดที่เป็นปัญหาเป็นส่วนหนึ่งของไลบรารี MooTools ที่แพร่หลาย จึงมีความเป็นไปได้ว่าเว็บไซต์จำนวนมากจะได้รับผลกระทบ (แม้ว่า MooTools จะไม่นิยมใช้กับเว็บไซต์ใหม่ในปี 2018 แต่เดิมแล้ว MooTools เป็นที่นิยมอย่างมากและยังคงมีอยู่ในเว็บไซต์เวอร์ชันที่ใช้งานจริงหลายแห่ง)
ผู้เขียนข้อเสนอแนะนำอย่างติดตลกให้เปลี่ยนชื่อ flatten
เป็น smoosh
เพื่อหลีกเลี่ยงปัญหาความเข้ากันได้ มุกตลกนี้ไม่ชัดเจนสำหรับทุกคน บางคนเริ่มเข้าใจผิดว่าชื่อใหม่ได้รับการตัดสินใจแล้ว และเรื่องก็บานปลายอย่างรวดเร็ว
Array.prototype.flatten
ทำอะไรได้บ้าง
Array.prototype.flat
ซึ่งเดิมเรียกว่า Array.prototype.flatten
จะยุบอาร์เรย์แบบซ้ำซ้อนจนถึง depth
ที่ระบุ ซึ่งค่าเริ่มต้นคือ 1
// Flatten one level:
const array = [1, [2, [3]]];
array.flat();
// → [1, 2, [3]]
// Flatten recursively until the array contains no more nested arrays:
array.flat(Infinity);
// → [1, 2, 3]
ข้อเสนอเดียวกันนี้ยังมี Array.prototype.flatMap
ซึ่งคล้ายกับ Array.prototype.map
ยกเว้นว่าจะแปลงผลลัพธ์ให้เป็นอาร์เรย์ใหม่
[2, 3, 4].flatMap((x) => [x, x * 2]);
// → [2, 4, 3, 6, 4, 8]
MooTools กำลังทําอะไรอยู่จึงทำให้เกิดปัญหานี้
MooTools กำหนด Array.prototype.flatten
เวอร์ชันที่ไม่ใช่มาตรฐานของตนเอง ดังนี้
Array.prototype.flatten = /* non-standard implementation */;
การใช้งาน flatten
ของ MooTools แตกต่างจากมาตรฐานที่เสนอ
แต่นี่ไม่ใช่ปัญหา เมื่อเบราว์เซอร์มีArray.prototype.flatten
การใช้งานแบบดั้งเดิม MooTools จะลบล้างการใช้งานแบบดั้งเดิม วิธีนี้ช่วยให้มั่นใจได้ว่าโค้ดที่อาศัยลักษณะการทํางานของ MooTools จะทํางานตามที่ตั้งใจไว้ ไม่ว่า flatten
เนทีฟจะพร้อมใช้งานหรือไม่ก็ตาม
จนถึงตอนนี้ทุกอย่างเรียบร้อยดี
แต่แล้วก็มีเหตุการณ์อื่นเกิดขึ้น MooTools จะคัดลอกเมธอดอาร์เรย์ที่กำหนดเองทั้งหมดไปยัง Elements.prototype
(โดยที่ Elements
เป็น API สำหรับ MooTools โดยเฉพาะ)
for (var key in Array.prototype) {
Elements.prototype[key] = Array.prototype[key];
}
for
-in
วนซ้ำพร็อพเพอร์ตี้ "ที่นับได้" ซึ่งไม่รวมเมธอดเดิม เช่น Array.prototype.sort
แต่รวมพร็อพเพอร์ตี้ที่กำหนดเป็นประจำ เช่น Array.prototype.foo = whatever
แต่ประเด็นสำคัญคือ หากคุณเขียนทับพร็อพเพอร์ตี้ที่ไม่ใช่แบบแจกแจง เช่น Array.prototype.sort = whatever
พร็อพเพอร์ตี้ดังกล่าวจะยังคงไม่ใช่แบบแจกแจง
ปัจจุบัน Array.prototype.flatten = mooToolsFlattenImplementation
จะสร้างพร็อพเพอร์ตี้ flatten
ที่นับได้ ดังนั้นระบบจะคัดลอกไปยัง Elements
ในภายหลัง แต่หากเบราว์เซอร์จัดส่ง flatten
เวอร์ชันเนทีฟ flatten
จะไม่สามารถแจกแจงได้ และจะไม่คัดลอกไปยัง Elements
โค้ดใดก็ตามที่อาศัย Elements.prototype.flatten
ของ MooTools จะใช้งานไม่ได้
แม้ว่าการเปลี่ยน Array.prototype.flatten
เดิมให้เป็นแบบที่เรียกข้อมูลได้จะช่วยแก้ปัญหาได้ แต่ก็มีแนวโน้มที่จะทำให้เกิดปัญหาความเข้ากันได้มากขึ้น เว็บไซต์ทุกแห่งที่ใช้ for
-in
เพื่อวนซ้ำผ่านอาร์เรย์ (ซึ่งเป็นแนวทางปฏิบัติที่ไม่ถูกต้อง แต่เกิดขึ้นได้) จะได้รับการเพิ่มการวนซ้ำของลูปสำหรับพร็อพเพอร์ตี้ flatten
อย่างกะทันหัน
ปัญหาที่ใหญ่กว่าคือ การแก้ไขออบเจ็กต์ในตัว ปัจจุบันการขยายโปรโตไทป์แบบเนทีฟถือเป็นแนวทางปฏิบัติที่ไม่ถูกต้อง เนื่องจากทำงานร่วมกับไลบรารีอื่นๆ และโค้ดของบุคคลที่สามได้ไม่ดี อย่าแก้ไขวัตถุที่คุณไม่ได้เป็นเจ้าของ
ทำไมเราไม่ใช้ชื่อเดิมต่อไปและทำให้เว็บพังไปเลยล่ะ
ในปี 1996 ก่อนที่ CSS จะแพร่หลาย และก่อนที่ "HTML5" จะกลายเป็นที่นิยม เว็บไซต์ Space Jam ได้เปิดตัว ปัจจุบันเว็บไซต์ดังกล่าวยังคงทำงานเหมือนเดิมเหมือนเมื่อ 22 ปีก่อน
เหตุใดจึงเกิดขึ้น มีเจ้าหน้าที่ดูแลเว็บไซต์ดังกล่าวตลอดหลายปีที่ผ่านมาไหม โดยอัปเดตทุกครั้งที่ผู้ให้บริการเบราว์เซอร์เปิดตัวฟีเจอร์ใหม่
ปรากฏว่า "อย่าทำให้เว็บใช้งานไม่ได้" เป็นหลักการการออกแบบอันดับ 1 สำหรับ HTML, CSS, JavaScript และมาตรฐานอื่นๆ ที่ใช้กันอย่างแพร่หลายในเว็บ หากการเปิดตัวฟีเจอร์ใหม่ในเบราว์เซอร์ทําให้เว็บไซต์ที่มีอยู่หยุดทํางาน สิ่งต่างๆ จะส่งผลเสียต่อทุกคนดังนี้
- ผู้เข้าชมเว็บไซต์ที่ได้รับผลกระทบได้รับประสบการณ์การใช้งานที่ใช้งานไม่ได้อย่างกะทันหัน
- เจ้าของเว็บไซต์มีเว็บไซต์ที่ทํางานได้อย่างสมบูรณ์แบบแต่กลับกลายเป็นเว็บไซต์ที่ไม่ทํางานโดยที่เจ้าของไม่ได้เปลี่ยนแปลงอะไรเลย
- ผู้ให้บริการเบราว์เซอร์ที่เปิดตัวฟีเจอร์ใหม่จะสูญเสียส่วนแบ่งการตลาดเนื่องจากผู้ใช้เปลี่ยนไปใช้เบราว์เซอร์อื่นหลังจากสังเกตเห็นว่า "ฟีเจอร์นี้ใช้งานได้ในเบราว์เซอร์ X"
- เมื่อทราบปัญหาด้านความเข้ากันได้แล้ว ผู้ให้บริการเบราว์เซอร์รายอื่นๆ ปฏิเสธที่จะจัดส่ง ข้อกำหนดของฟีเจอร์ไม่ตรงกับความเป็นจริง ("เป็นเพียงเรื่องแต่ง") ซึ่งส่งผลเสียต่อกระบวนการมาตรฐาน
แน่นอนว่าเมื่อมองย้อนกลับไป MooTools ได้ทำสิ่งที่ไม่ถูกต้อง แต่การทำให้เว็บใช้งานไม่ได้ไม่ได้เป็นการลงโทษ MooTools แต่เป็นการลงโทษผู้ใช้ ผู้ใช้เหล่านี้ไม่ทราบว่า Moo Tool คืออะไร หรือเราจะหาวิธีแก้ปัญหาอื่นก็ได้ และผู้ใช้จะใช้งานเว็บต่อได้ การเลือกนั้นง่ายมาก
Does that mean bad APIs can never be removed from the Web Platform?
แล้วแต่กรณี ในบางกรณีที่เกิดขึ้นไม่บ่อยนัก ระบบอาจนำฟีเจอร์ที่เป็นอันตรายออกจากเว็บ แม้แต่การระบุว่าเป็นไปได้หรือไม่ที่จะนำฟีเจอร์ออกก็เป็นเรื่องที่ซับซ้อนมาก และต้องอาศัยการวัดผลที่ครอบคลุมเพื่อประเมินจำนวนหน้าเว็บที่จะมีการเปลี่ยนแปลงลักษณะการทำงาน แต่ในกรณีที่ฟีเจอร์ไม่ปลอดภัยมากพอ เป็นอันตรายต่อผู้ใช้ หรือมีการใช้งานน้อยมาก การดำเนินการนี้สามารถทำได้
<applet>
, <keygen>
และ showModalDialog()
ล้วนเป็นตัวอย่างของ API ที่ไม่ถูกต้องซึ่งนําออกจากแพลตฟอร์มเว็บได้สําเร็จ
ทำไมไม่แก้ไข MooTools เลย
การแพตช์ MooTools เพื่อไม่ให้ขยายออบเจ็กต์ในตัวอีกต่อไปเป็นแนวคิดที่ดี แต่วิธีนี้ไม่ได้แก้ปัญหาที่เกิดขึ้น แม้ว่า MooTools จะเปิดตัวเวอร์ชันที่แพตช์แล้ว แต่เว็บไซต์ทั้งหมดที่ใช้ MooTools อยู่จะต้องอัปเดตเพื่อให้ปัญหาความเข้ากันได้หายไป
ผู้ใช้อัปเดต MooTools ที่ใช้อยู่ไม่ได้หรือ
หากทุกอย่างเป็นไปตามที่ควรจะเป็น MooTools จะปล่อยแพตช์ และเว็บไซต์ทุกแห่งที่ใช้ MooTools จะอัปเดตโดยอัตโนมัติในวันถัดไป ปัญหาได้รับการแก้ไขแล้ว ถูกต้องไหม
ขออภัย การดำเนินการนี้ไม่สามารถทำได้ แม้ว่าจะมีผู้ระบุเว็บไซต์ทั้งหมดที่ได้รับผลกระทบ ค้นหาข้อมูลติดต่อของเว็บไซต์แต่ละแห่ง ติดต่อเจ้าของเว็บไซต์ทั้งหมดได้สำเร็จ และโน้มน้าวให้เจ้าของเว็บไซต์ทั้งหมดทำการอัปเดต (ซึ่งอาจหมายถึงการปรับโครงสร้างโค้ดทั้งหมด) แต่กระบวนการทั้งหมดนี้อาจใช้เวลาหลายปี
โปรดทราบว่าเว็บไซต์เหล่านี้จำนวนมากเป็นเว็บไซต์เก่าและอาจไม่มีการบำรุงรักษา แม้ว่าผู้ดูแลจะยังอยู่ แต่บุคคลดังกล่าวอาจไม่ใช่นักพัฒนาเว็บที่มีความเชี่ยวชาญสูงเหมือนคุณ เราไม่สามารถคาดหวังให้ทุกคนเปลี่ยนแปลงเว็บไซต์ที่มีอายุ 8 ปีเนื่องจากปัญหาความเข้ากันได้ของเว็บ
กระบวนการของ TC39 ทำงานอย่างไร
TC39 เป็นคณะกรรมการที่รับผิดชอบการพัฒนาภาษา JavaScript ผ่านมาตรฐาน ECMAScript
#SmooshGate ทำให้บางคนเชื่อว่า "TC39 ต้องการเปลี่ยนชื่อ flatten
เป็น smoosh
" แต่จริงๆ แล้วเป็นมุกตลกภายในที่สื่อสารกับภายนอกได้ไม่ชัดเจน
การตัดสินใจที่สำคัญ เช่น การเปลี่ยนชื่อโปรเจ็กต์ ไม่ใช่การตัดสินใจที่ดำเนินการโดยพลการ ไม่ใช่การตัดสินใจที่ดำเนินการโดยบุคคลเพียงคนเดียว และไม่ใช่การตัดสินใจที่ดำเนินการในชั่วข้ามคืนโดยอิงตามความคิดเห็นเดียวใน GitHub
TC39 ดำเนินการตามกระบวนการเตรียมความพร้อมที่ชัดเจนสำหรับข้อเสนอฟีเจอร์
ข้อเสนอ ECMAScript และการเปลี่ยนแปลงที่สำคัญ (รวมถึงการเปลี่ยนชื่อเมธอด) จะได้รับการพูดคุยกันในการประชุม TC39 และต้องได้รับอนุมัติจากคณะกรรมการทั้งหมดก่อนที่จะมีผลอย่างเป็นทางการ ในกรณีของ Array.prototype.flatten
ข้อเสนอผ่านขั้นตอนต่างๆ ของข้อตกลงแล้วจนถึงระยะที่ 3 ซึ่งบ่งบอกว่าฟีเจอร์พร้อมใช้งานในเว็บเบราว์เซอร์ ปัญหาเกี่ยวกับข้อกําหนดเพิ่มเติมเกิดขึ้นได้ในระหว่างการติดตั้งใช้งาน ในกรณีนี้ ความคิดเห็นที่สําคัญที่สุดคือความคิดเห็นที่ได้รับหลังจากพยายามเปิดตัวฟีเจอร์ดังกล่าว เนื่องจากฟีเจอร์ดังกล่าวในสถานะปัจจุบันทำให้เว็บใช้งานไม่ได้ ปัญหาที่คาดการณ์ได้ยากเช่นนี้เป็นหนึ่งในเหตุผลที่กระบวนการ TC39 ไม่ได้สิ้นสุดลงเมื่อเบราว์เซอร์เปิดตัวฟีเจอร์
TC39 ทำงานแบบฉันทามติ ซึ่งหมายความว่าคณะกรรมการต้องเห็นด้วยกับการเปลี่ยนแปลงใหม่ แม้ว่า smoosh
จะเป็นชื่อที่จริงจัง แต่สมาชิกคณะกรรมการก็อาจคัดค้านชื่อนี้และต้องการชื่อที่เข้าใจง่ายกว่า เช่น compact
หรือ chain
การเปลี่ยนชื่อจาก flatten
เป็น smoosh
(แม้ว่าจะไม่ใช่เรื่องตลก) ไม่เคยมีการพูดคุยกันในการประชุม TC39 ดังนั้น ขณะนี้เรายังไม่ทราบจุดยืนอย่างเป็นทางการของ TC39 เกี่ยวกับหัวข้อนี้ บุคคลใดบุคคลหนึ่งไม่สามารถพูดในนามของ TC39 ทั้งหมดได้จนกว่าจะมีมติเป็นเอกฉันกันในการประชุมครั้งถัดไป
โดยทั่วไปแล้ว การประชุม TC39 จะมีผู้เข้าร่วมที่มาจากหลากหลายภูมิหลัง เช่น บางคนมีประสบการณ์การออกแบบภาษาโปรแกรมมาหลายปี บางคนทํางานเกี่ยวกับเบราว์เซอร์หรือเครื่องมือ JavaScript และมีผู้เข้าร่วมจำนวนมากขึ้นที่เข้าร่วมเพื่อแสดงถึงชุมชนนักพัฒนาซอฟต์แวร์ JavaScript
SmooshGate ได้รับการแก้ไขแล้วหรือยัง
ในช่วงการประชุม TC39 ของเดือนพฤษภาคม 2018 ปัญหา #SmooshGate ได้สิ้นสุดลงอย่างเป็นทางการด้วยการเปลี่ยนชื่อ flatten
เป็น flat
Array.prototype.flat
และ Array.prototype.flatMap
พร้อมใช้งานใน V8 v6.9 และ Chrome 69