มีอีกวิธีหนึ่งในการสร้างฟังก์ชัน ไม่ค่อยได้ใช้แต่บางครั้งก็ไม่มีทางเลือกอื่น
ไวยากรณ์สำหรับการสร้างฟังก์ชัน:
ให้ func = ฟังก์ชั่นใหม่ ([arg1, arg2, ...argN], functionBody);
ฟังก์ชันนี้ถูกสร้างขึ้นด้วยอาร์กิวเมนต์ arg1...argN
และ functionBody
ที่กำหนด
ง่ายต่อการเข้าใจโดยดูตัวอย่าง นี่คือฟังก์ชันที่มีสองอาร์กิวเมนต์:
ให้ sum = new Function('a', 'b', 'return a + b'); การแจ้งเตือน( ผลรวม(1, 2) ); // 3
และนี่คือฟังก์ชันที่ไม่มีอาร์กิวเมนต์ มีเพียงส่วนของฟังก์ชันเท่านั้น:
ให้ sayHi = new Function('alert("Hello")'); พูดว่าสวัสดี(); // สวัสดี
ความแตกต่างที่สำคัญจากวิธีอื่นๆ ที่เราเคยเห็นคือ ฟังก์ชันนี้ถูกสร้างขึ้นตามตัวอักษรจากสตริงที่ถูกส่งผ่านขณะรันไทม์
การประกาศก่อนหน้านี้ทั้งหมดกำหนดให้เราซึ่งเป็นโปรแกรมเมอร์ต้องเขียนโค้ดฟังก์ชันในสคริปต์
แต่ new Function
ช่วยให้สามารถเปลี่ยนสตริงใด ๆ ให้เป็นฟังก์ชันได้ ตัวอย่างเช่น เราสามารถรับฟังก์ชันใหม่จากเซิร์ฟเวอร์แล้วดำเนินการได้:
ให้ str = ... รับรหัสจากเซิร์ฟเวอร์แบบไดนามิก ... ให้ func = ฟังก์ชั่นใหม่ (str); ฟังก์ชั่น();
มันถูกใช้ในกรณีที่เฉพาะเจาะจงมาก เช่น เมื่อเราได้รับโค้ดจากเซิร์ฟเวอร์ หรือเพื่อคอมไพล์ฟังก์ชันแบบไดนามิกจากเทมเพลต ในเว็บแอปพลิเคชันที่ซับซ้อน
โดยปกติแล้ว ฟังก์ชั่นจะจดจำตำแหน่งที่เกิดในคุณสมบัติพิเศษ [[Environment]]
มันอ้างอิงถึงสภาพแวดล้อมของคำศัพท์จากที่ที่มันถูกสร้างขึ้น (เราได้กล่าวถึงในบทขอบเขตตัวแปร การปิด)
แต่เมื่อฟังก์ชันถูกสร้างขึ้นโดยใช้ new Function
[[Environment]]
ของฟังก์ชันนั้นจะถูกตั้งค่าให้อ้างอิงไม่ใช่สภาพแวดล้อมของคำศัพท์ในปัจจุบัน แต่เป็นฟังก์ชันส่วนกลาง
ดังนั้นฟังก์ชันดังกล่าวไม่สามารถเข้าถึงตัวแปรภายนอกได้เฉพาะตัวแปรส่วนกลางเท่านั้น
ฟังก์ชัน getFunc() { ให้ค่า = "ทดสอบ"; ให้ func = new Function('alert(value)'); ฟังก์ชั่นส่งคืน; - getFunc()(); // ข้อผิดพลาด: ไม่ได้กำหนดค่าไว้
เปรียบเทียบกับพฤติกรรมปกติ:
ฟังก์ชัน getFunc() { ให้ค่า = "ทดสอบ"; ให้ func = function() { การแจ้งเตือน (ค่า); - ฟังก์ชั่นส่งคืน; - getFunc()(); // "test" จากสภาพแวดล้อมคำศัพท์ของ getFunc
คุณสมบัติพิเศษของ new Function
ดูแปลกแต่กลับมีประโยชน์มากในทางปฏิบัติ
ลองนึกภาพว่าเราต้องสร้างฟังก์ชันจากสตริง โค้ดของฟังก์ชันนั้นไม่เป็นที่รู้จักในขณะที่เขียนสคริปต์ (นั่นคือสาเหตุที่เราไม่ใช้ฟังก์ชันปกติ) แต่จะเป็นที่รู้จักในกระบวนการดำเนินการ เราอาจได้รับจากเซิร์ฟเวอร์หรือจากแหล่งอื่น
ฟังก์ชั่นใหม่ของเราต้องโต้ตอบกับสคริปต์หลัก
จะเกิดอะไรขึ้นถ้ามันสามารถเข้าถึงตัวแปรภายนอกได้?
ปัญหาคือก่อนที่จะเผยแพร่ JavaScript สู่การใช้งานจริง JavaScript จะถูกบีบอัดโดยใช้ ตัวย่อ ซึ่งเป็นโปรแกรมพิเศษที่จะย่อขนาดโค้ดโดยการลบความคิดเห็นพิเศษ การเว้นวรรค และสิ่งสำคัญคือเปลี่ยนชื่อตัวแปรในเครื่องให้สั้นลง
ตัวอย่างเช่น หากฟังก์ชันอนุญาตให้ let userName
ตัวย่อจะแทนที่ด้วย let a
(หรือตัวอักษรอื่นหากฟังก์ชันนี้ถูกครอบครอง) และดำเนินการทุกที่ โดยปกติแล้วจะเป็นสิ่งที่ปลอดภัย เนื่องจากตัวแปรเป็นแบบโลคัล จึงไม่มีสิ่งใดนอกฟังก์ชันเข้าถึงได้ และภายในฟังก์ชัน ตัวย่อจะเข้ามาแทนที่ทุกการกล่าวถึง ตัวย่อนั้นฉลาด โดยวิเคราะห์โครงสร้างโค้ด ดังนั้นจึงไม่ทำลายสิ่งใดๆ พวกเขาไม่ใช่แค่การค้นหาและแทนที่ที่โง่เขลา
ดังนั้นหาก new Function
สามารถเข้าถึงตัวแปรภายนอกได้ ก็จะไม่สามารถค้นหา userName
ที่เปลี่ยนชื่อได้
หาก new Function
สามารถเข้าถึงตัวแปรภายนอกได้ ก็จะมีปัญหากับตัวย่อ
นอกจากนี้โค้ดดังกล่าวอาจมีสถาปัตยกรรมที่ไม่ดีและมีแนวโน้มที่จะเกิดข้อผิดพลาด
ในการส่งต่อบางสิ่งไปยังฟังก์ชันที่สร้างขึ้นเป็น new Function
เราควรใช้อาร์กิวเมนต์ของมัน
ไวยากรณ์:
ให้ func = ฟังก์ชั่นใหม่ ([arg1, arg2, ...argN], functionBody);
ด้วยเหตุผลทางประวัติศาสตร์ อาจกำหนดให้อาร์กิวเมนต์เป็นรายการที่คั่นด้วยเครื่องหมายจุลภาคได้
คำประกาศทั้งสามนี้มีความหมายเหมือนกัน:
ฟังก์ชั่นใหม่ ('a', 'b', 'return a + b'); // ไวยากรณ์พื้นฐาน ฟังก์ชั่นใหม่ ('a, b', 'return a + b'); //คั่นด้วยเครื่องหมายจุลภาค ฟังก์ชั่นใหม่ ('a , b', 'return a + b'); // คั่นด้วยเครื่องหมายจุลภาคด้วยช่องว่าง
ฟังก์ชั่นที่สร้างขึ้นด้วย new Function
มี [[Environment]]
อ้างอิงถึงสภาพแวดล้อมคำศัพท์ส่วนกลาง ไม่ใช่ภายนอก ดังนั้นจึงไม่สามารถใช้ตัวแปรภายนอกได้ แต่นั่นเป็นสิ่งที่ดีจริงๆ เพราะมันประกันเราจากข้อผิดพลาด การส่งพารามิเตอร์อย่างชัดเจนเป็นวิธีการที่ดีกว่ามากในเชิงสถาปัตยกรรม และไม่มีปัญหากับตัวย่อ