1. ใช้ตัวแปรทั่วโลกเพื่อบันทึกกรณีเดียว
นี่เป็นวิธีที่ง่ายที่สุดในการใช้งาน
ฟังก์ชันบุคคล () {this.createTime = วันที่ใหม่ (); } var อินสแตนซ์ = คนใหม่ (); ฟังก์ชั่น getInstance () {return instance; -เมื่อโหลด js นี้วัตถุบุคคลจะถูกสร้างและบันทึกลงในตัวแปรอินสแตนซ์สากล วัตถุนี้ใช้ทุกครั้งที่ใช้ หากคุณไม่ได้ใช้มันเพียงครั้งเดียววัตถุที่คุณสร้างนั้นสูญเปล่าเราสามารถปรับให้เหมาะสมได้
ฟังก์ชันอินสแตนซ์ var getInstance () {ถ้า (! อินสแตนซ์) {อินสแตนซ์ = บุคคลใหม่ (); } return อินสแตนซ์; -ด้วยวิธีนี้วัตถุจะถูกสร้างขึ้นเมื่อใช้เป็นครั้งแรก
ข้อเสียของวิธีนี้คืออินสแตนซ์เป็นตัวแปรทั่วโลก เมื่อหลายคนร่วมมือกันหรือวงจรการพัฒนาค่อนข้างยาวมันเป็นเรื่องยากที่จะตรวจสอบให้แน่ใจว่าอินสแตนซ์จะไม่ได้รับการแก้ไขหรือเขียนทับด้วยรหัสอื่น ๆ มีความเป็นไปได้สูงที่เมื่อเรียกว่าการโทรพบว่าอินสแตนซ์ไม่ใช่วัตถุบุคคลเลย
ลองพิจารณาใช้การปิดเพื่อห่อหุ้มอินสแตนซ์เพื่อไม่ให้ตัวแปรระดับโลกอีกต่อไปในการแก้ปัญหานี้
2. วัตถุการสร้างปิด
var getInstance () {อินสแตนซ์ var; return function () {ถ้า (! อินสแตนซ์) {อินสแตนซ์ = คนใหม่ (); } return อินสแตนซ์; -ด้วยวิธีนี้อินสแตนซ์จะถูกห่อหุ้มและไม่จำเป็นต้องกังวลเกี่ยวกับการแก้ไข
ตอนนี้คุณสามารถรับซิงเกิลผ่านฟังก์ชั่น GetInstance () คำถามใหม่ถ้าฉันสร้างวัตถุผ่านบุคคลใหม่ () ฉันยังคงได้รับวัตถุหลายอย่างและ JavaScript ไม่สามารถแปรรูปตัวสร้างเช่น Java ได้ ดังนั้นเราจะสร้างวัตถุที่เป็นใหม่ได้อย่างไรหลายครั้งเป็นอินสแตนซ์?
3. อินสแตนซ์แคชแอตทริบิวต์คงที่ของตัวสร้าง
ดูรหัสก่อน
ฟังก์ชันบุคคล () {// ถ้าอินสแตนซ์ถูกแคชมันจะส่งคืนอินสแตนซ์แคชโดยตรงถ้า (typeof person.instance === 'วัตถุ') {return person.instance; } this.createTime = วันที่ใหม่ (); // cacheed instance person.instance = this; คืนสิ่งนี้; -จากรหัสเราจะเห็นว่าครั้งแรกใหม่เงื่อนไขของการส่งคืน false จะลงไปเริ่มต้นวัตถุแล้วบันทึกวัตถุไปยังบุคคลที่มีคุณสมบัติคงที่
ครั้งที่สองใหม่เงื่อนไขของการส่งคืนจริงส่งคืนบุคคลโดยตรง. instance และรหัสที่เริ่มต้นจะไม่ถูกเรียกใช้ ดังนั้นไม่ว่าวัตถุใหม่กี่ครั้งวัตถุที่ส่งคืนเป็นวัตถุที่สร้างขึ้นครั้งแรก
ข้อเสียของวิธีนี้เหมือนกับวิธีหนึ่ง Person.instance ยังเป็นทรัพย์สินสาธารณะและอาจได้รับการแก้ไข
มาอ้างถึงวิธีการ 2. การใช้การปิดเพื่อห่อหุ้มหนึ่งอาจแก้ปัญหาได้
4. เขียนตัวสร้างใหม่
วิธีนี้ต้องใช้การปิด แต่ก็ไม่สามารถทำได้ง่ายเหมือนวิธีที่สอง เราจำเป็นต้องแทนที่ตัวสร้าง
ฟังก์ชันบุคคล () {// อินสแตนซ์อินสแตนซ์ var ที่แคช = สิ่งนี้; this.createTime = วันที่ใหม่ (); // เขียนตัวสร้าง person = function () {return instance; -ครั้งแรกที่มีการเรียกว่าตัวสร้างดั้งเดิมจะถูกแคชก่อนแล้วเริ่มต้นและเริ่มต้นและตัวสร้างจะถูกแทนที่ เมื่อใหม่ในอนาคตตัวสร้างดั้งเดิมจะไม่ถูกเรียกและตัวสร้างใหม่สามารถเรียกได้เท่านั้นและฟังก์ชั่นนี้จะส่งคืนอินสแตนซ์แคชเสมอ
วิธีการข้างต้นดูเหมือนจะดี แต่ผ่านการทดสอบต่อไปนี้คุณสามารถค้นหาปัญหาได้
// เพิ่ม person.prototype.prop1 = true; var p1 = คนใหม่ (); // หลังจากสร้างวัตถุเริ่มต้นให้เพิ่ม person.prototype.prop2 = true; var p2 = คนใหม่ (); // เริ่มต้นทดสอบคอนโซลล็อก (p1.prop1); // ผลลัพธ์คือจริงคอนโซล log (p2.prop1); // ผลลัพธ์คือคอนโซลจริง log (p1.prop2); // ผลลัพธ์คือคอนโซลที่ไม่ได้กำหนด (p2.prop2); // console.log (p1.constructor === บุคคล); // ผลลัพธ์คือ false console.log (p2.constructor === บุคคล); // ผลลัพธ์เป็นเท็จ
ผลลัพธ์ที่คาดหวังควรเป็นจริง
วิเคราะห์รหัสทดสอบข้างต้น
person.prototype.prop1 = true; เพิ่มแอตทริบิวต์ PROP1 ภายใต้ต้นแบบของคอนสตรัคเตอร์ดั้งเดิมและกำหนดค่า
หลังจากดำเนินการ var p1 = บุคคลใหม่ ();, ตัวสร้างบุคคลได้รับการเขียนใหม่
ดังนั้น person.prototype.prop2 = true; เพิ่มคุณสมบัติ PROP2 ภายใต้ต้นแบบใหม่
var p2 = คนใหม่ (); P2 และ P1 เป็นวัตถุเดียวกันนั่นคือวัตถุที่สร้างโดยตัวสร้างดั้งเดิม
ดังนั้น P1 และ P2 จึงมีคุณสมบัติ prop1 แต่ไม่มีคุณสมบัติ prop2
ในทำนองเดียวกันตัวสร้างของ P1 และ P2 ยังชี้ไปที่ตัวสร้างดั้งเดิมและบุคคลไม่ได้เป็นฟังก์ชั่นดั้งเดิมอีกต่อไปในเวลานี้
เพื่อที่จะทำงานตามที่คาดไว้การแก้ไขบางอย่างสามารถทำได้
ฟังก์ชันบุคคล () {// อินสแตนซ์อินสแตนซ์ var ที่แคช = สิ่งนี้; // rewrite structor person = function () {return instance; } // สำรองตัวคุณลักษณะต้นแบบ person.prototype = this; // อินสแตนซ์ = คนใหม่ (); // รีเซ็ตอินสแตนซ์อ้างอิงตัวสร้าง. constructor = บุคคล; // อินสแตนซ์การเริ่มต้นอื่น ๆ createTime = วันที่ใหม่ (); อินสแตนซ์กลับ; -เรียกใช้รหัสทดสอบก่อนหน้าและผลลัพธ์เป็นจริง
5. ขี้เกียจโหลด:
ในโครงการขนาดใหญ่หรือซับซ้อนมันมีบทบาทในการเพิ่มประสิทธิภาพ: ส่วนประกอบที่มีราคาแพง แต่ไม่ค่อยได้ใช้สามารถห่อเป็นซิงเกิลที่กำลังโหลดได้อย่างขี้เกียจโปรแกรมตัวอย่าง:
/ * ซิงเกิลตันกับสมาชิกส่วนตัวขั้นตอนที่ 3. */mynamespace.singleton = (ฟังก์ชั่น () {// สมาชิกส่วนตัว var privateattribute1 = false; var privateattribute2 = [1, 2, 3]; ฟังก์ชั่น privateemethod1 () {... } PublicMethod1: function () {... }, PublicMethod2: ฟังก์ชั่น (args) {... }};}) ();/ * โครงกระดูกทั่วไปสำหรับ singleton ที่กำลังโหลดขี้เกียจ, ขั้นตอนที่ 1. */mynamespace.singleton = (ฟังก์ชั่น croptructor Privateattribute2 = [1, 2, 3]; ฟังก์ชั่น PrivateMethod1 () {... } privateMethod2 (args) {... } return {// สมาชิกสาธารณะ Singleton ที่กำลังโหลดขี้เกียจ, ขั้นตอนที่ 2. */mynamespace.singleton = (ฟังก์ชั่น () {function constructor () {// รหัสซิงเกิลปกติทั้งหมดไปที่นี่ ... } return {getInstance: function () {// // รหัสควบคุมไปที่นี่}}}) () (function () {var UniqueInstance; // แอตทริบิวต์ส่วนตัวที่เก็บอินสแตนซ์เดียวฟังก์ชั่น constructor () {// รหัสซิงเกิลปกติทั้งหมดไปที่นี่ ... } return {getInstance: function () {ถ้า (! uniqueInstance) {// อินสแตนซ์เท่านั้น6. ใช้สาขา Singleton:
รหัสสำหรับสภาพแวดล้อมที่เฉพาะ
/ * simplexhractory singleton, ขั้นตอนที่ 1. */var simplexhractory = (ฟังก์ชั่น () {// สามสาขา. var standard = {createxhrobject: function () {return xmlhtttprequest () {returt new new new new new new new }}; var activexold = {createxhrobject: function () {return activexobject ใหม่ ('microsoft.xmlhttp'); xmlhttprequest ()}}; สาขาลองใช้วิธีการที่ไม่เคยมีมาก่อน activexold.createxhrobject ();