ไวยากรณ์ {...}
ปกติช่วยให้เราสามารถสร้างวัตถุเดียวได้ แต่บ่อยครั้งเราจำเป็นต้องสร้างออบเจ็กต์ที่คล้ายกันหลายอย่าง เช่น ผู้ใช้หลายรายหรือรายการเมนูเป็นต้น
ซึ่งสามารถทำได้โดยใช้ฟังก์ชันคอนสตรัคเตอร์และตัวดำเนินการ "new"
ฟังก์ชันตัวสร้างในทางเทคนิคแล้วเป็นฟังก์ชันปกติ มีสองแบบแผนแม้ว่า:
ตั้งชื่อด้วยตัวพิมพ์ใหญ่ก่อน
ควรดำเนินการด้วยตัวดำเนินการ "new"
เท่านั้น
ตัวอย่างเช่น:
ผู้ใช้ฟังก์ชัน (ชื่อ) { this.name = ชื่อ; this.isAdmin = เท็จ; - ให้ผู้ใช้ = ผู้ใช้ใหม่ ("แจ็ค"); การแจ้งเตือน (ชื่อผู้ใช้); //แจ็ค การแจ้งเตือน (user.isAdmin); // เท็จ
เมื่อฟังก์ชันถูกดำเนินการด้วย new
มันจะทำตามขั้นตอนต่อไปนี้:
ออบเจ็กต์ว่างใหม่ถูกสร้างขึ้นและกำหนดให้กับ this
เนื้อหาของฟังก์ชันดำเนินการ โดยปกติแล้วจะแก้ไข this
เพิ่มคุณสมบัติใหม่เข้าไป
ค่าของ this
จะถูกส่งกลับ
กล่าวอีกนัยหนึ่ง new User(...)
ทำหน้าที่ดังนี้:
ผู้ใช้ฟังก์ชัน (ชื่อ) { // นี่ = {}; (โดยปริยาย) // เพิ่มคุณสมบัตินี้ this.name = ชื่อ; this.isAdmin = เท็จ; // คืนสิ่งนี้; (โดยปริยาย) -
ดังนั้น let user = new User("Jack")
ให้ผลลัพธ์เหมือนกับ:
ให้ผู้ใช้ = { ชื่อ: "แจ็ค", isAdmin: เท็จ -
ตอนนี้หากเราต้องการสร้างผู้ใช้รายอื่น เราสามารถเรียก new User("Ann")
, new User("Alice")
และอื่นๆ สั้นกว่าการใช้ตัวอักษรทุกครั้งมาก และยังอ่านง่ายอีกด้วย
นั่นคือจุดประสงค์หลักของตัวสร้าง - เพื่อใช้โค้ดการสร้างวัตถุที่นำมาใช้ซ้ำได้
โปรดทราบอีกครั้งว่า ในทางเทคนิคแล้ว ฟังก์ชันใดๆ (ยกเว้นฟังก์ชันลูกศร เนื่องจากไม่มี this
) สามารถใช้เป็นตัวสร้างได้ มันสามารถรันด้วย new
และมันจะรันอัลกอริธึมด้านบน “อักษรตัวพิมพ์ใหญ่ต้องมาก่อน” เป็นข้อตกลงทั่วไป เพื่อให้ชัดเจนว่าจะต้องรันฟังก์ชันด้วย new
ฟังก์ชั่นใหม่ () { … }
หากเรามีโค้ดหลายบรรทัดเกี่ยวกับการสร้างอ็อบเจ็กต์ที่ซับซ้อนเพียงอันเดียว เราก็สามารถรวมโค้ดเหล่านั้นไว้ในฟังก์ชัน Constructor ที่เรียกว่าทันที เช่นนี้:
// สร้างฟังก์ชั่นแล้วเรียกมันด้วย new ทันที ให้ผู้ใช้ = ฟังก์ชั่นใหม่ () { this.name = "จอห์น"; this.isAdmin = เท็จ; // ...โค้ดอื่นๆ สำหรับการสร้างผู้ใช้ // อาจเป็นตรรกะและข้อความที่ซับซ้อน // ตัวแปรท้องถิ่น ฯลฯ -
ไม่สามารถเรียก Constructor นี้ได้อีก เนื่องจากไม่ได้บันทึกไว้ที่ใดเลย เพียงแค่สร้างและเรียกใช้เท่านั้น ดังนั้นเคล็ดลับนี้จึงมีจุดมุ่งหมายเพื่อห่อหุ้มโค้ดที่สร้างออบเจ็กต์เดี่ยวโดยไม่ต้องนำกลับมาใช้ใหม่ในอนาคต
สิ่งขั้นสูง
ไวยากรณ์จากส่วนนี้ไม่ค่อยได้ใช้ โปรดข้ามไปเว้นแต่คุณต้องการทราบทุกอย่าง
ภายในฟังก์ชัน เราสามารถตรวจสอบได้ว่ามันถูกเรียกด้วย new
หรือไม่มีเลย โดยใช้คุณสมบัติพิเศษ new.target
ไม่ได้กำหนดไว้สำหรับการโทรปกติและเท่ากับฟังก์ชันหากเรียกใช้ด้วย new
:
ผู้ใช้ฟังก์ชัน () { การแจ้งเตือน (new.target); - // ไม่มี "ใหม่": ผู้ใช้(); // ไม่ได้กำหนด // ด้วย "ใหม่": ผู้ใช้ใหม่(); // ผู้ใช้ฟังก์ชัน { ... }
ที่สามารถใช้ภายในฟังก์ชั่นเพื่อให้รู้ว่ามันถูกเรียกด้วย new
“ในโหมด Constructor” หรือไม่ใช้ “ในโหมดปกติ”
นอกจากนี้เรายังสามารถโทรออกทั้ง new
และปกติเพื่อทำเช่นเดียวกัน เช่นนี้
ผู้ใช้ฟังก์ชัน (ชื่อ) { if (!new.target) { // ถ้าคุณเรียกใช้ฉันโดยไม่ต้องใหม่ ส่งคืนผู้ใช้ใหม่ (ชื่อ); // ...ฉันจะเพิ่มใหม่ให้กับคุณ - this.name = ชื่อ; - ให้ john = User("John"); // เปลี่ยนเส้นทางการโทรไปยังผู้ใช้ใหม่ การแจ้งเตือน (john.name); // จอห์น
บางครั้งวิธีนี้ใช้ในไลบรารีเพื่อทำให้ไวยากรณ์มีความยืดหยุ่นมากขึ้น เพื่อให้ผู้คนสามารถเรียกใช้ฟังก์ชันนี้โดยมีหรือไม่มี new
และยังคงใช้งานได้
อาจไม่ใช่สิ่งที่ดีที่จะใช้ทุกที่ เนื่องจากการละเว้น new
จะทำให้ไม่ชัดเจนว่าเกิดอะไรขึ้น ด้วย new
เราทุกคนรู้ว่าวัตถุใหม่กำลังถูกสร้างขึ้น
โดยปกติแล้วตัวสร้างจะไม่มีคำสั่ง return
หน้าที่ของพวกเขาคือเขียนสิ่งที่จำเป็นทั้งหมดลงใน this
และผลลัพธ์จะกลายเป็นผลลัพธ์โดยอัตโนมัติ
แต่หากมีคำสั่ง return
กฎก็ง่ายๆ:
หากเรียก return
ด้วยอ็อบเจ็กต์ ก็แสดงว่าอ็อบเจ็กต์นั้นถูกส่งคืนแทน this
ถ้า return
ถูกเรียกด้วยค่าพื้นฐาน ก็จะถูกละเว้น
กล่าวอีกนัยหนึ่ง return
พร้อมกับอ็อบเจ็กต์จะส่งคืนอ็อบเจ็กต์นั้น ในกรณีอื่น ๆ this
จะถูกส่งคืน
ตัวอย่างเช่น ที่นี่ return
จะแทนที่ this
โดยการส่งคืนอ็อบเจ็กต์:
ฟังก์ชั่น BigUser() { this.name = "จอห์น"; กลับ { ชื่อ: "Godzilla" }; // <-- ส่งคืนวัตถุนี้ - alert( ใหม่ BigUser().name ); //ก็อดซิลล่าได้วัตถุนั้นมา
และนี่คือตัวอย่างที่มี return
เป็นค่าว่าง (หรือเราจะใส่ค่าดั้งเดิมตามหลังก็ได้ ไม่สำคัญ):
ฟังก์ชั่น SmallUser() { this.name = "จอห์น"; กลับ; // <-- ส่งคืนสิ่งนี้ - alert( new SmallUser().name ); // จอห์น
โดยทั่วไปแล้วตัวสร้างจะไม่มีคำสั่ง return
ในที่นี้เราจะกล่าวถึงพฤติกรรมพิเศษกับการส่งคืนออบเจ็กต์เพื่อความสมบูรณ์เป็นหลัก
ละเว้นวงเล็บ
อย่างไรก็ตาม เราสามารถละเว้นวงเล็บหลังจาก new
:
ให้ผู้ใช้ = ผู้ใช้ใหม่; // <-- ไม่มีวงเล็บ //เหมือนกับ. ให้ผู้ใช้ = ผู้ใช้ใหม่ ();
การละวงเล็บในที่นี้ไม่ถือเป็น "สไตล์ที่ดี" แต่อนุญาตให้ใช้ไวยากรณ์ได้ตามข้อกำหนด
การใช้ฟังก์ชันคอนสตรัคเตอร์เพื่อสร้างออบเจ็กต์ให้ความยืดหยุ่นอย่างมาก ฟังก์ชัน Constructor อาจมีพารามิเตอร์ที่กำหนดวิธีสร้างออบเจ็กต์ และสิ่งที่ต้องใส่ในนั้น
แน่นอนว่าเราสามารถเพิ่มไม่เพียงแต่คุณสมบัติ this
แต่ยังรวมถึงวิธีการด้วย
ตัวอย่างเช่น new User(name)
ด้านล่างจะสร้างวัตถุที่มี name
ที่กำหนดและวิธีการ sayHi
:
ผู้ใช้ฟังก์ชัน (ชื่อ) { this.name = ชื่อ; this.sayHi = ฟังก์ชั่น () { alert( "ฉันชื่อ: " + this.name ); - - ให้ john = ผู้ใช้ใหม่ ("จอห์น"); john.sayHi(); // ฉันชื่อ: จอห์น - จอห์น = { ชื่อ: "จอห์น" พูดสวัสดี: function() { ... } - -
ในการสร้างวัตถุที่ซับซ้อน มีไวยากรณ์และคลาสขั้นสูงที่เราจะกล่าวถึงในภายหลัง
ฟังก์ชัน Constructor หรือเรียกสั้น ๆ ว่า Constructor เป็นฟังก์ชันปกติ แต่มีข้อตกลงทั่วไปในการตั้งชื่อฟังก์ชันด้วยตัวพิมพ์ใหญ่ก่อน
ฟังก์ชัน Constructor ควรเรียกใช้โดยใช้ new
เท่านั้น การเรียกดังกล่าวหมายถึงการสร้างค่าว่าง this
ตั้งแต่เริ่มต้น และส่งคืนค่าที่เติมไว้ในตอนท้าย
เราสามารถใช้ฟังก์ชัน Constructor เพื่อสร้างวัตถุที่คล้ายกันหลายๆ ชิ้นได้
JavaScript มีฟังก์ชัน Constructor สำหรับออบเจ็กต์ภาษาในตัวมากมาย เช่น Date
สำหรับวันที่ Set
สำหรับเซต และอื่นๆ ที่เราวางแผนจะศึกษา
วัตถุ เราจะกลับมา!
ในบทนี้เราจะครอบคลุมเฉพาะพื้นฐานเกี่ยวกับวัตถุและตัวสร้างเท่านั้น สิ่งเหล่านี้จำเป็นสำหรับการเรียนรู้เพิ่มเติมเกี่ยวกับประเภทข้อมูลและฟังก์ชันในบทถัดไป
หลังจากที่เราเรียนรู้สิ่งนั้นแล้ว เราจะกลับไปที่วัตถุและครอบคลุมพวกมันในเชิงลึกในบท Prototypes, inheritance และ Classes
ความสำคัญ: 2
เป็นไปได้ไหมที่จะสร้างฟังก์ชัน A
และ B
เพื่อให้ new A() == new B()
?
ฟังก์ชัน A() { ... } ฟังก์ชัน B() { ... } ให้ a = ใหม่ A(); ให้ b = B ใหม่ (); การแจ้งเตือน (a == b); // จริง
หากเป็นเช่นนั้น ให้ยกตัวอย่างโค้ดของพวกเขา
ใช่มันเป็นไปได้
หากฟังก์ชันส่งคืนอ็อบเจ็กต์ new
จะส่งกลับแทน this
ดังนั้นพวกเขาสามารถส่งคืนวัตถุที่กำหนดจากภายนอกเดียวกันได้ obj
:
ให้ obj = {}; ฟังก์ชั่น A() { กลับ obj; - ฟังก์ชั่น B() { กลับ obj; - การแจ้งเตือน ( A ใหม่ () == B ใหม่ () ); // จริง
ความสำคัญ: 5
สร้างฟังก์ชันคอนสตรัคเตอร์ Calculator
ที่สร้างวัตถุด้วย 3 วิธี:
read()
พร้อมท์ให้ใส่ค่าสองค่าและบันทึกเป็นคุณสมบัติของวัตถุที่มีชื่อ a
และ b
ตามลำดับ
sum()
ส่งคืนผลรวมของคุณสมบัติเหล่านี้
mul()
ส่งคืนผลคูณของคุณสมบัติเหล่านี้
ตัวอย่างเช่น:
ให้เครื่องคิดเลข = เครื่องคิดเลขใหม่ (); เครื่องคิดเลขอ่าน(); alert( "Sum=" + Calculator.sum() ); alert( "Mul=" + Calculator.mul() );
เรียกใช้การสาธิต
เปิดแซนด์บ็อกซ์พร้อมการทดสอบ
ฟังก์ชั่นเครื่องคิดเลข() { นี้.อ่าน = ฟังก์ชั่น() { this.a = +prompt('a?', 0); this.b = +พร้อมท์('b?', 0); - this.sum = ฟังก์ชั่น () { กลับ this.a + this.b; - นี้.mul = ฟังก์ชั่น() { กลับ this.a * this.b; - - ให้เครื่องคิดเลข = เครื่องคิดเลขใหม่ (); เครื่องคิดเลขอ่าน(); alert( "Sum=" + Calculator.sum() ); alert( "Mul=" + Calculator.mul() );
เปิดโซลูชันพร้อมการทดสอบในแซนด์บ็อกซ์
ความสำคัญ: 5
สร้างฟังก์ชันคอนสตรัคเตอร์ Accumulator(startingValue)
วัตถุที่มันสร้างขึ้นควร:
เก็บ "มูลค่าปัจจุบัน" ไว้ใน value
ทรัพย์สิน ค่าเริ่มต้นถูกกำหนดเป็นอาร์กิวเมนต์ของตัวสร้าง startingValue
เมธอด read()
ควรใช้ prompt
เพื่ออ่านตัวเลขใหม่และเพิ่มลงใน value
กล่าวอีกนัยหนึ่ง คุณสมบัติ value
คือผลรวมของค่าที่ผู้ใช้ป้อนทั้งหมดกับค่าเริ่มต้น startingValue
นี่คือการสาธิตรหัส:
ให้ accumulator = ตัวสะสมใหม่ (1); // ค่าเริ่มต้น 1 สะสม.อ่าน(); // เพิ่มค่าที่ผู้ใช้ป้อน สะสม.อ่าน(); // เพิ่มค่าที่ผู้ใช้ป้อน การแจ้งเตือน(accumulator.value); // แสดงผลรวมของค่าเหล่านี้
เรียกใช้การสาธิต
เปิดแซนด์บ็อกซ์พร้อมการทดสอบ
ฟังก์ชั่นสะสม (ราคาเริ่มต้น) { this.value = ค่าเริ่มต้น; นี้.อ่าน = ฟังก์ชั่น() { this.value += +prompt('ต้องเพิ่มเท่าไหร่?', 0); - - ให้ accumulator = ตัวสะสมใหม่ (1); สะสม.อ่าน(); สะสม.อ่าน(); การแจ้งเตือน(accumulator.value);
เปิดโซลูชันพร้อมการทดสอบในแซนด์บ็อกซ์