วิธีที่ง่ายที่สุด / สะอาดที่สุดในการใช้รูปแบบซิงเกิลตันใน JavaScript คืออะไร?
วิธีที่ง่ายที่สุด / สะอาดที่สุดในการใช้รูปแบบซิงเกิลตันใน JavaScript คืออะไร?
คำตอบ:
ฉันคิดว่าวิธีที่ง่ายที่สุดคือการประกาศวัตถุตามตัวอักษรอย่างง่าย:
var myInstance = {
method1: function () {
// ...
},
method2: function () {
// ...
}
};
หากคุณต้องการสมาชิกส่วนตัวในอินสแตนซ์เดี่ยวของคุณคุณสามารถทำสิ่งนี้:
var myInstance = (function() {
var privateVar = '';
function privateMethod () {
// ...
}
return { // public interface
publicMethod1: function () {
// all private members are accessible here
},
publicMethod2: function () {
}
};
})();
นี้ได้รับการเรียกรูปแบบโมดูลนั้นโดยทั่วไปจะช่วยให้คุณแค็ปซูลส่วนตัวของสมาชิกบนวัตถุโดยการใช้ประโยชน์การใช้งานของการปิด
UPDATE:ฉันต้องการเพิ่มว่าถ้าคุณต้องการป้องกันการดัดแปลงวัตถุเดี่ยวคุณสามารถตรึงโดยใช้Object.freeze
วิธีES5
ที่จะทำให้วัตถุไม่เปลี่ยนรูปป้องกันการเปลี่ยนแปลงใด ๆ กับโครงสร้างและค่าของมัน
นอกจากนี้ฉันอยากจะพูดถึงว่าถ้าคุณใช้ ES6 คุณสามารถเป็นตัวแทนของซิงเกิลที่ใช้ES Modulesได้อย่างง่ายดายและคุณยังสามารถเก็บสถานะส่วนตัวด้วยการประกาศตัวแปรที่ขอบเขตโมดูล :
// my-singleton.js
const somePrivateState = []
function privateFn () {
// ...
}
export default {
method1() {
// ...
},
method2() {
// ...
}
}
จากนั้นคุณสามารถนำเข้าวัตถุ singleton เพื่อใช้งานได้:
import myInstance from './my-singleton.js'
// ...
publicMethod1
โทรได้publicMethod2
อย่างไร
getInstance
วิธีการคงที่และตัวสร้างส่วนตัว - แต่ IMO นี่เป็นวิธีที่ "ง่าย" ที่สุดในการสร้างวัตถุเดี่ยว ใน Javascript และท้ายที่สุดมันก็มีจุดประสงค์เดียวกันคือวัตถุเดียวที่คุณไม่สามารถเริ่มต้นใหม่ได้ (ไม่มีตัวสร้างมันเป็นเพียงวัตถุ) - เกี่ยวกับรหัสที่คุณเชื่อมโยงก็มีปัญหาบางอย่างสลับa
และประกาศตัวแปรและการทดสอบb
a === window
ไชโย
ฉันคิดว่าวิธีที่สะอาดที่สุดคือ:
var SingletonFactory = (function(){
function SingletonClass() {
//do stuff
}
var instance;
return {
getInstance: function(){
if (instance == null) {
instance = new SingletonClass();
// Hide the constructor so the returned object can't be new'd...
instance.constructor = null;
}
return instance;
}
};
})();
หลังจากนั้นคุณสามารถเรียกใช้ฟังก์ชันเป็น
var test = SingletonFactory.getInstance();
delete instance.constructor
:x = SingletonClass.getInstance();delete x.constructor;new x.constructor;
ฉันไม่แน่ใจว่าฉันเห็นด้วยกับรูปแบบโมดูลที่ใช้แทนรูปแบบซิงเกิล ฉันเคยเห็น singletons ใช้และถูกทารุณกรรมในสถานที่ที่พวกเขาไม่จำเป็นทั้งหมดและฉันแน่ใจว่ารูปแบบโมดูลเติมช่องว่างมากมายที่โปรแกรมเมอร์จะใช้ singleton แต่รูปแบบโมดูลไม่ใช่แบบซิงเกิล
var foo = (function () {
"use strict";
function aPrivateFunction() {}
return { aPublicFunction: function () {...}, ... };
}());
ทุกอย่างเริ่มต้นในรูปแบบโมดูลเกิดขึ้นเมื่อFoo
มีการประกาศ นอกจากนี้รูปแบบโมดูลสามารถใช้ในการเริ่มต้นคอนสตรัคเตอร์ซึ่งสามารถสร้างอินสแตนซ์ได้หลายครั้ง ในขณะที่รูปแบบโมดูลเป็นเครื่องมือที่เหมาะสมสำหรับงานจำนวนมาก แต่ไม่เทียบเท่ากับซิงเกิลตัน
var Foo = function () {
"use strict";
if (Foo._instance) {
//this allows the constructor to be called multiple times
//and refer to the same instance. Another option is to
//throw an error.
return Foo._instance;
}
Foo._instance = this;
//Foo initialization code
};
Foo.getInstance = function () {
"use strict";
return Foo._instance || new Foo();
}
แบบยาวโดยใช้รูปแบบโมดูล
var Foo = (function () {
"use strict";
var instance; //prevent modification of "instance" variable
function Singleton() {
if (instance) {
return instance;
}
instance = this;
//Singleton initialization code
}
//instance accessor
Singleton.getInstance = function () {
return instance || new Singleton();
}
return Singleton;
}());
ในทั้งสองรูปแบบของรูปแบบซิงเกิลที่ฉันให้ไว้คอนสตรัคเองสามารถใช้เป็น accessor:
var a,
b;
a = new Foo(); //constructor initialization happens here
b = new Foo();
console.log(a === b); //true
หากคุณรู้สึกไม่สบายใจกับการใช้ Constructor ด้วยวิธีนี้คุณสามารถโยนข้อผิดพลาดในif (instance)
ข้อความสั่งและใช้รูปแบบยาว:
var a,
b;
a = Foo.getInstance(); //constructor initialization happens here
b = Foo.getInstance();
console.log(a === b); //true
ฉันควรพูดถึงว่ารูปแบบซิงเกิลเหมาะกับรูปแบบฟังก์ชั่นคอนสตรัคของนัย:
function Foo() {
if (Foo._instance) {
return Foo._instance;
}
//if the function wasn't called as a constructor,
//call it as a constructor and return the result
if (!(this instanceof Foo)) {
return new Foo();
}
Foo._instance = this;
}
var f = new Foo(); //calls Foo as a constructor
-or-
var f = Foo(); //also calls Foo as a constructor
var singleton = {}
ไม่พอดีกับคำจำกัดความที่
var singleton = {}
เป็นวิธีที่คุณใช้เดี่ยวใน Javascript
ในes6
:
class Singleton {
constructor () {
if (!Singleton.instance) {
Singleton.instance = this
}
// Initialize object
return Singleton.instance
}
// Properties & Methods
}
const instance = new Singleton()
Object.freeze(instance)
export default instance
instance
ฟิลด์เท่านั้น เนื่องจากขณะนี้ ( instance
ตั้งค่าเป็นthis
) คลาสนี้อาจมีฟิลด์อื่นเช่นกันและการแช่แข็งไม่สมเหตุสมผล
การทำงานต่อไปนี้ในโหนด v6
class Foo {
constructor(msg) {
if (Foo.singleton) {
return Foo.singleton;
}
this.msg = msg;
Foo.singleton = this;
return Foo.singleton;
}
}
เราทดสอบ:
const f = new Foo('blah');
const d = new Foo('nope');
console.log(f); // => Foo { msg: 'blah' }
console.log(d); // => Foo { msg: 'blah' }
ใน ES6 วิธีที่ถูกต้องคือ:
class MyClass {
constructor() {
if (MyClass._instance) {
throw new Error("Singleton classes can't be instantiated more than once.")
}
MyClass._instance = this;
// ... your rest of the constructor code goes after this
}
}
var instanceOne = new MyClass() // Executes succesfully
var instanceTwo = new MyClass() // Throws error
หรือหากคุณไม่ต้องการให้เกิดข้อผิดพลาดในการสร้างอินสแตนซ์ที่สองคุณสามารถส่งคืนอินสแตนซ์สุดท้ายได้เช่น:
class MyClass {
constructor() {
if (MyClass._instance) {
return MyClass._instance
}
MyClass._instance = this;
// ... your rest of the constructor code goes after this
}
}
var instanceOne = new MyClass()
var instanceTwo = new MyClass()
console.log(instanceOne === instanceTwo) // logs "true"
instance
_instance
มันเป็นเพียงแค่การตั้งชื่อในภาษาการเขียนโปรแกรมที่เราตั้งชื่อตัวแปรส่วนตัวที่มีเครื่องหมายขีดล่าง ฉันสงสัยว่าสาเหตุที่ทำให้รหัสของคุณไม่ทำงานคือคุณใช้this.instance
แทนMyClass.instance
มีมากกว่าหนึ่งวิธีในการสกินแมว :) ขึ้นอยู่กับรสนิยมหรือความต้องการเฉพาะของคุณคุณสามารถใช้วิธีแก้ปัญหาที่เสนอ ฉันจะไปหาทางออกแรกของ CMS เมื่อทำได้ (เมื่อคุณไม่ต้องการความเป็นส่วนตัว) เนื่องจากคำถามเกี่ยวกับสิ่งที่ง่ายและสะอาดที่สุดนั่นคือผู้ชนะ หรือแม้กระทั่ง:
var myInstance = {}; // done!
นี่ (อ้างจากบล็อกของฉัน) ...
var SingletonClass = new function() {
this.myFunction() {
//do stuff
}
this.instance = 1;
}
ไม่สมเหตุสมผล (ตัวอย่างบล็อกของฉันไม่ได้เป็นอย่างใดอย่างหนึ่ง) เพราะมันไม่จำเป็นต้องมี vars ส่วนตัวดังนั้นมันจึงค่อนข้างเหมือนกับ:
var SingletonClass = {
myFunction: function () {
//do stuff
},
instance: 1
}
this.f(){}
ฉันเลิกตอบคำถามแล้วดูคำตอบของฉันคนอื่น
โดยปกติรูปแบบโมดูล (ดูคำตอบ CMS ') ซึ่งไม่ใช่รูปแบบซิงเกิลดีพอ อย่างไรก็ตามหนึ่งในคุณสมบัติของซิงเกิลตันคือการเริ่มต้นนั้นจะล่าช้าจนกว่าวัตถุจะต้องการ รูปแบบโมดูลขาดคุณสมบัตินี้
ข้อเสนอของฉัน (CoffeeScript):
window.singleton = (initializer) ->
instance = undefined
() ->
return instance unless instance is undefined
instance = initializer()
ซึ่งรวบรวมไว้ใน JavaScript:
window.singleton = function(initializer) {
var instance;
instance = void 0;
return function() {
if (instance !== void 0) {
return instance;
}
return instance = initializer();
};
};
จากนั้นฉันสามารถทำสิ่งต่อไปนี้:
window.iAmSingleton = singleton(function() {
/* This function should create and initialize singleton. */
alert("creating");
return {property1: 'value1', property2: 'value2'};
});
alert(window.iAmSingleton().property2); // "creating" will pop up; then "value2" will pop up
alert(window.iAmSingleton().property2); // "value2" will pop up but "creating" will not
window.iAmSingleton().property2 = 'new value';
alert(window.iAmSingleton().property2); // "new value" will pop up
เนื่องจากลักษณะที่ไม่มีการปิดกั้นของ JavaScript, Singletons ใน JavaScript มีการใช้งานที่น่าเกลียดจริงๆ ตัวแปรทั่วโลกจะให้อินสแตนซ์เดียวแก่คุณผ่านแอปพลิเคชันทั้งหมดโดยไม่มีการเรียกกลับทั้งหมดรูปแบบโมดูลจะซ่อนภายในอินเทอร์เฟซ ดูคำตอบ @CMS
แต่เนื่องจากคุณต้องการซิงเกิล ...
var singleton = function(initializer) {
var state = 'initial';
var instance;
var queue = [];
var instanceReady = function(createdInstance) {
state = 'ready';
instance = createdInstance;
while (callback = queue.shift()) {
callback(instance);
}
};
return function(callback) {
if (state === 'initial') {
state = 'waiting';
queue.push(callback);
initializer(instanceReady);
} else if (state === 'waiting') {
queue.push(callback);
} else {
callback(instance);
}
};
};
การใช้งาน:
var singletonInitializer = function(instanceReady) {
var preparedObject = {property: 'value'};
// calling instanceReady notifies singleton that instance is ready to use
instanceReady(preparedObject);
}
var s = singleton(singletonInitializer);
// get instance and use it
s(function(instance) {
instance.doSomething();
});
Singletons ให้คุณมากกว่าหนึ่งอินสแตนซ์ผ่านแอปพลิเคชันทั้งหมด: การกำหนดค่าเริ่มต้นของพวกเขาล่าช้าจนถึงการใช้ครั้งแรก นี่เป็นเรื่องใหญ่จริง ๆ เมื่อคุณจัดการกับวัตถุที่การเริ่มต้นมีราคาแพง โดยปกติแพงหมายถึง I / O และใน JavaScript I / O มักหมายถึงการโทรกลับ
อย่าเชื่อคำตอบที่ให้อินเทอร์เฟซกับinstance = singleton.getInstance()
คุณพวกเขาทุกคนพลาดจุดสำคัญ
หากพวกเขาไม่ได้รับการเรียกกลับให้ทำงานเมื่ออินสแตนซ์พร้อมแล้วพวกเขาจะไม่ทำงานเมื่อ initializer ใช้ I / O
ใช่การเรียกกลับจะดูน่าเกลียดกว่าการเรียกใช้ฟังก์ชันซึ่งจะส่งคืนอินสแตนซ์ของวัตถุทันที แต่อีกครั้ง: เมื่อคุณทำ I / O การเรียกกลับเป็นสิ่งที่จำเป็น หากคุณไม่ต้องการทำ I / O ใด ๆ การสร้างอินสแตนซ์นั้นมีราคาถูกพอที่จะเริ่มต้นโปรแกรมได้
var simpleInitializer = function(instanceReady) {
console.log("Initializer started");
instanceReady({property: "initial value"});
}
var simple = singleton(simpleInitializer);
console.log("Tests started. Singleton instance should not be initalized yet.");
simple(function(inst) {
console.log("Access 1");
console.log("Current property value: " + inst.property);
console.log("Let's reassign this property");
inst.property = "new value";
});
simple(function(inst) {
console.log("Access 2");
console.log("Current property value: " + inst.property);
});
ในตัวอย่างนี้ทำให้setTimeout
การดำเนินการ I / O มีราคาแพง นี่แสดงให้เห็นว่าเหตุใดซิงเกิลใน JavaScript ต้องการการเรียกกลับ
var heavyInitializer = function(instanceReady) {
console.log("Initializer started");
var onTimeout = function() {
console.log("Initializer did his heavy work");
instanceReady({property: "initial value"});
};
setTimeout(onTimeout, 500);
};
var heavy = singleton(heavyInitializer);
console.log("In this example we will be trying");
console.log("to access singleton twice before it finishes initialization.");
heavy(function(inst) {
console.log("Access 1");
console.log("Current property value: " + inst.property);
console.log("Let's reassign this property");
inst.property = "new value";
});
heavy(function(inst) {
console.log("Access 2. You can see callbacks order is preserved.");
console.log("Current property value: " + inst.property);
});
console.log("We made it to the end of the file. Instance is not ready yet.");
ฉันได้ตัวอย่างนี้จากรูปแบบ JavaScript สร้างแอปพลิเคชันที่ดีขึ้นด้วยการเข้ารหัสและรูปแบบการออกแบบโดยหนังสือของStoyan Stefanovในกรณีที่คุณต้องการคลาสการใช้งานอย่างง่ายเช่นวัตถุ singltone คุณสามารถใช้ฟังก์ชั่นได้ทันทีดังนี้
var ClassName;
(function() {
var instance;
ClassName = function ClassName() {
//If private instance variable already initialized return reference
if(instance) {
return instance;
}
//If instance does not created save pointer of original reference
//to private instance variable.
instance = this;
//All constructor initialization will be here
// i.e.:
this.someProperty = 0;
this.someMethod = function() {
//Some action here
};
};
}());
และคุณสามารถตรวจสอบตัวอย่างนี้โดยกรณีทดสอบต่อไปนี้:
//Extending defined class like Singltone object using new prototype property
ClassName.prototype.nothing = true;
var obj_1 = new ClassName();
//Extending defined class like Singltone object using new prototype property
ClassName.prototype.everything = true;
var obj_2 = new ClassName();
//Testing does this two object pointing to same instance
console.log(obj_1 === obj_2); //Result is true, it points to same instance object
//All prototype properites work
//no matter when they were defined
console.log(obj_1.nothing && obj_1.everything
&& obj_2.nothing && obj_2.everything); //Result true
//Values of properties which is defined inside of constructor
console.log(obj_1.someProperty);// output 0
console.log(obj_2.someProperty);// output 0
//Changing property value
obj_1.someProperty = 1;
console.log(obj_1.someProperty);// output 1
console.log(obj_2.someProperty);// output 1
console.log(obj_1.constructor === ClassName); //Output true
วิธีนี้ผ่านทุกกรณีทดสอบในขณะที่การใช้งานแบบสแตติกส่วนตัวจะล้มเหลวเมื่อมีการใช้ส่วนขยายต้นแบบ (สามารถแก้ไขได้ แต่จะไม่ง่าย) และการใช้งานสแตติกแบบสาธารณะแนะนำให้เลือกน้อยลงเนื่องจากมีการเปิดเผยต่อสาธารณะ
ฉันคิดว่าฉันพบวิธีที่ดีที่สุดในการเขียนโปรแกรมใน JavaScript แต่คุณต้องมีจินตนาการ ฉันได้รับแนวคิดนี้จากเทคนิคการทำงานในหนังสือ "ส่วนที่ดีจาวาสคริปต์"
แทนที่จะใช้คำหลักใหม่คุณสามารถสร้างคลาสดังนี้:
function Class()
{
var obj = {}; // Could also be used for inheritence if you don't start with an empty object.
var privateVar;
obj.publicVar;
obj.publicMethod= publicMethod;
function publicMethod(){}
function privateMethod(){}
return obj;
}
คุณสามารถยกตัวอย่างวัตถุด้านบนโดยพูดว่า:
var objInst = Class(); // !!! NO NEW KEYWORD
ในขณะนี้ด้วยวิธีการทำงานนี้ในใจคุณสามารถสร้างซิงเกิลตันแบบนี้:
ClassSingleton = function()
{
var instance= null;
function Class() // This is the class like the above one
{
var obj = {};
return obj;
}
function getInstance()
{
if( !instance )
instance = Class(); // Again no new keyword;
return instance;
}
return { getInstance : getInstance };
}();
ตอนนี้คุณสามารถรับอินสแตนซ์ของคุณโดยการโทร
var obj = ClassSingleton.getInstance();
ฉันคิดว่านี่เป็นวิธีที่เรียบร้อยที่สุดเพราะไม่สามารถเข้าถึง "คลาส" ที่สมบูรณ์ได้
@CMS และ @zzzzBov ทั้งคู่ต่างให้คำตอบที่ยอดเยี่ยม แต่เพียงเพิ่มการตีความของตัวเองตามการย้ายไปสู่การพัฒนาต่อมน้ำอย่างหนักจาก PHP / Zend Framework ที่รูปแบบซิงเกิลทั่วไป
รหัสที่แสดงความคิดเห็นต่อไปนี้เป็นไปตามข้อกำหนดต่อไปนี้:
รหัสของฉันคล้ายกับ @ zzzzBov มากยกเว้นว่าฉันได้เพิ่มเชนต้นแบบให้กับคอนสตรัคเตอร์และความคิดเห็นเพิ่มเติมที่จะช่วยให้ผู้ที่มาจาก PHP หรือภาษาที่คล้ายกันแปล OOP ดั้งเดิมเป็นธรรมชาติของจาวาสคริปต์ มันอาจไม่ใช่ "ง่ายที่สุด" แต่ฉันเชื่อว่าเหมาะสมที่สุด
// declare 'Singleton' as the returned value of a self-executing anonymous function
var Singleton = (function () {
"use strict";
// 'instance' and 'constructor' should not be availble in a "public" scope
// here they are "private", thus available only within
// the scope of the self-executing anonymous function
var _instance=null;
var _constructor = function (name) {
this.name = name || 'default';
}
// prototypes will be "public" methods available from the instance
_constructor.prototype.getName = function () {
return this.name;
}
// using the module pattern, return a static object
// which essentially is a list of "public static" methods
return {
// because getInstance is defined within the same scope
// it can access the "private" 'instance' and 'constructor' vars
getInstance:function (name) {
if (!_instance) {
console.log('creating'); // this should only happen once
_instance = new _constructor(name);
}
console.log('returning');
return _instance;
}
}
})(); // self execute
// ensure 'instance' and 'constructor' are unavailable
// outside the scope in which they were defined
// thus making them "private" and not "public"
console.log(typeof _instance); // undefined
console.log(typeof _constructor); // undefined
// assign instance to two different variables
var a = Singleton.getInstance('first');
var b = Singleton.getInstance('second'); // passing a name here does nothing because the single instance was already instantiated
// ensure 'a' and 'b' are truly equal
console.log(a === b); // true
console.log(a.getName()); // "first"
console.log(b.getName()); // also returns "first" because it's the same instance as 'a'
โปรดทราบว่าในทางเทคนิคแล้วฟังก์ชั่นที่ไม่เปิดเผยตัวตนของผู้ใช้งานจะเป็น Singleton ดังที่แสดงไว้ในรหัสที่ได้รับจาก @CMS สิ่งเดียวที่จับได้ที่นี่คือมันเป็นไปไม่ได้ที่จะแก้ไขต้นแบบลูกโซ่ของนวกรรมิกเมื่อนวกรรมิกเองไม่ระบุชื่อ
โปรดทราบว่าสำหรับ Javascript แนวคิดของ "สาธารณะ" และ "ส่วนตัว" ไม่สามารถใช้งานได้เช่นเดียวกับใน PHP หรือ Java แต่เราได้รับผลกระทบที่เหมือนกันโดยใช้ประโยชน์จากกฎความพร้อมใช้งานของขอบเขต Javascript
var a = Singleton.getInstance('foo'); var b = new a.constructor('bar');
ไม่แน่ใจว่าทำไมไม่มีใครนำเรื่องนี้ขึ้นมา แต่คุณสามารถทำได้:
var singleton = new (function() {
var bar = 123
this.foo = function() {
// whatever
}
})()
คำตอบที่ชัดเจนควรเป็นคำนี้จากหนังสือ Learning ลวดลายการออกแบบ JavaScript โดย Addy Osmani
var mySingleton = (function () {
// Instance stores a reference to the Singleton
var instance;
function init() {
// Singleton
// Private methods and variables
function privateMethod(){
console.log( "I am private" );
}
var privateVariable = "Im also private";
var privateRandomNumber = Math.random();
return {
// Public methods and variables
publicMethod: function () {
console.log( "The public can see me!" );
},
publicProperty: "I am also public",
getRandomNumber: function() {
return privateRandomNumber;
}
};
};
return {
// Get the Singleton instance if one exists
// or create one if it doesn't
getInstance: function () {
if ( !instance ) {
instance = init();
}
return instance;
}
};
})();
ฉันเชื่อว่านี่เป็นวิธีที่ง่ายที่สุด / สะอาดที่สุดและใช้งานง่ายที่สุดแม้ว่าจะต้องใช้ ES7:
export default class Singleton { static instance; constructor(){ if(instance){ return instance; } this.state = "duke"; this.instance = this; } }
ซอร์สโค้ดมาจาก: adam-bien.com
new Singleton()
เกิดอะไรขึ้นกับสิ่งนี้?
function Klass() {
var instance = this;
Klass = function () { return instance; }
}
Test = Klass; t1 = new Test(); t2 = new Test();
- ไม่มีโอกาสเปลี่ยนชื่อคลาสหรือเลือกเนมสเปซอื่น
ฉันสามารถใส่ 5 เหรียญของฉันได้ไหม ฉันมีฟังก์ชั่นตัวสร้างเช่น
var A = function(arg1){
this.arg1 = arg1
};
สิ่งที่ฉันต้องทำคือวัตถุทุกชิ้นที่สร้างโดย CF นี้จะเหมือนกัน
var X = function(){
var instance = {};
return function(){ return instance; }
}();
ทดสอบ
var x1 = new X();
var x2 = new X();
console.log(x1 === x2)
ฉันพบว่าสิ่งต่อไปนี้เป็นรูปแบบซิงเกิลที่ง่ายที่สุดเพราะการใช้ตัวดำเนินการใหม่ทำให้สิ่งนี้สามารถใช้ได้ทันทีภายในฟังก์ชั่นที่ไม่จำเป็นต้องส่งคืนวัตถุตัวอักษร:
var singleton = new (function () {
var private = "A private value";
this.printSomething = function() {
console.log(private);
}
})();
singleton.printSomething();
นี่เป็นตัวอย่างง่าย ๆ ในการอธิบายรูปแบบซิงเกิลใน javascript
var Singleton=(function(){
var instance;
var init=function(){
return {
display:function(){
alert("This is a Singleton patern demo");
}
};
};
return {
getInstance:function(){
if(!instance){
alert("Singleton check");
instance=init();
}
return instance;
}
};
})();
// In this call first display alert("Singleton check")
// and then alert("This is a Singleton patern demo");
// It means one object is created
var inst=Singleton.getInstance();
inst.display();
// In this call only display alert("This is a Singleton patern demo")
// it means second time new object is not created,
// it uses the already created object
var inst1=Singleton.getInstance();
inst1.display();
ฉันต้องการซิงเกิลตันหลายอันด้วย:
และนี่คือสิ่งที่ฉันมาด้วย:
createSingleton ('a', 'add', [1, 2]);
console.log(a);
function createSingleton (name, construct, args) {
window[name] = {};
window[construct].apply(window[name], args);
window[construct] = null;
}
function add (a, b) {
this.a = a;
this.b = b;
this.sum = a + b;
}
args จะต้องเป็น Array เพื่อให้สิ่งนี้ทำงานได้ดังนั้นหากคุณมีตัวแปรว่างเปล่าให้ส่งค่าใน []
ฉันใช้วัตถุหน้าต่างในฟังก์ชัน แต่ฉันสามารถส่งผ่านพารามิเตอร์เพื่อสร้างขอบเขตของตัวเอง
พารามิเตอร์ name และ construct เป็นเพียง String สำหรับ window [] เพื่อให้ทำงานได้ แต่ด้วยการตรวจสอบประเภทอย่างง่าย window.name และ window.construct ก็สามารถทำได้เช่นกัน
วิธีการเกี่ยวกับวิธีนี้เพียงแค่ประกันชั้นไม่สามารถใหม่อีกครั้ง
โดยสิ่งนี้คุณสามารถใช้instanceof
op ได้เช่นกันคุณสามารถใช้ต้นแบบลูกโซ่เพื่อสืบทอดคลาสมันเป็นคลาสปกติ แต่ไม่สามารถใหม่ได้ถ้า yuu ต้องการรับอินสแตนซ์เพียงแค่ใช้getInstance
function CA()
{
if(CA.instance)
{
throw new Error('can not new this class');
}else{
CA.instance = this;
}
}
/**
* @protected
* @static
* @type {CA}
*/
CA.instance = null;
/** @static */
CA.getInstance = function()
{
return CA.instance;
}
CA.prototype =
/** @lends CA#*/
{
func: function(){console.log('the func');}
}
// initilize the instance
new CA();
// test here
var c = CA.getInstance()
c.func();
console.assert(c instanceof CA)
// this will failed
var b = new CA();
หากคุณไม่ต้องการเปิดเผยinstance
สมาชิกเพียงแค่ปิดสมาชิก
ต่อไปนี้เป็นตัวอย่างข้อมูลจากการเดินผ่านของฉันเพื่อใช้รูปแบบซิงเกิล เรื่องนี้เกิดขึ้นกับฉันในระหว่างการสัมภาษณ์และฉันรู้สึกว่าฉันควรจะจับมันที่ไหนซักแห่ง
/*************************************************
* SINGLETON PATTERN IMPLEMENTATION *
*************************************************/
//since there are no classes in javascript, every object is technically a singleton
//if you don't inherit from it or copy from it.
var single = {};
//Singleton Implementations
//Declaring as a Global Object...you are being judged!
var Logger = function() {
//global_log is/will be defined in GLOBAL scope here
if(typeof global_log === 'undefined'){
global_log = this;
}
return global_log;
};
//the below 'fix' solves the GLOABL variable problem but
//the log_instance is publicly available and thus can be
//tampered with.
function Logger() {
if(typeof Logger.log_instance === 'undefined'){
Logger.log_instance = this;
}
return Logger.log_instance;
};
//the correct way to do it to give it a closure!
function logFactory() {
var log_instance; //private instance
var _initLog = function() { //private init method
log_instance = 'initialized';
console.log("logger initialized!")
}
return {
getLog : function(){ //the 'privileged' method
if(typeof log_instance === 'undefined'){
_initLog();
}
return log_instance;
}
};
}
/***** TEST CODE ************************************************
//using the Logger singleton
var logger = logFactory();//did i just gave LogFactory a closure?
//create an instance of the logger
var a = logger.getLog();
//do some work
//get another instance of the logger
var b = logger.getLog();
//check if the two logger instances are same?
console.log(a === b); //true
*******************************************************************/
สามารถพบได้ในหน้าสรุปสาระสำคัญของฉัน
function Unicode()
{
var i = 0, unicode = {}, zero_padding = "0000", max = 9999;
//Loop through code points
while (i < max) {
//Convert decimal to hex value, find the character, then pad zeroes to the codepoint
unicode[String.fromCharCode(parseInt(i, 16))] = ("u" + zero_padding + i).substr(-4);
i = i + 1;
}
//Replace this function with the resulting lookup table
Unicode = unicode;
}
//Usage
Unicode();
//Lookup
Unicode["%"]; //returns 0025
นี่ไม่ใช่ซิงเกิลด้วยเหรอ?
function Singleton() {
var i = 0;
var self = this;
this.doStuff = function () {
i = i + 1;
console.log( 'do stuff',i );
};
Singleton = function () { return self };
return this;
}
s = Singleton();
s.doStuff();
คุณสามารถทำได้ด้วยการตกแต่งในตัวอย่างด้านล่างสำหรับ TypeScript:
class YourClass {
@Singleton static singleton() {}
}
function Singleton(target, name, descriptor) {
var instance;
descriptor.value = () => {
if(!instance) instance = new target;
return instance;
};
}
จากนั้นคุณใช้ซิงเกิลแบบนี้:
var myInstance = YourClass.singleton();
จากการเขียนนี้มัณฑนากรไม่พร้อมใช้งานในเครื่องมือ JavaScript คุณจะต้องแน่ใจว่า JavaScript runtime ของคุณเปิดใช้งานมัณฑนากรหรือใช้คอมไพเลอร์เช่น Babel และ TypeScript
โปรดทราบว่าอินสแตนซ์ซิงเกิลตันถูกสร้างขึ้น "สันหลังยาว" นั่นคือมันถูกสร้างขึ้นเฉพาะเมื่อคุณใช้เป็นครั้งแรก
รูปแบบโมดูล: ใน "สไตล์ที่อ่านได้มากขึ้น" คุณสามารถดูได้อย่างง่ายดายว่าวิธีใดเป็นสาธารณะและวิธีใดเป็นของเอกชน
var module = (function(_name){
/*Local Methods & Values*/
var _local = {
name : _name,
flags : {
init : false
}
}
function init(){
_local.flags.init = true;
}
function imaprivatemethod(){
alert("hi im a private method");
}
/*Public Methods & variables*/
var $r = {}; //this object will hold all public methods.
$r.methdo1 = function(){
console.log("method1 call it");
}
$r.method2 = function(){
imaprivatemethod(); //calling private method
}
$r.init = function(){
inti(); //making init public in case you want to init manually and not automatically
}
init(); //automatically calling init method
return $r; //returning all publics methods
})("module");
ตอนนี้คุณสามารถใช้วิธีสาธารณะเช่น
module.method2 (); // -> ฉันกำลังเรียกวิธีการส่วนตัวผ่านการแจ้งเตือนวิธีการสาธารณะ ("สวัสดีฉันเป็นวิธีการส่วนตัว")
ซิงเกิล:
ตรวจสอบให้แน่ใจว่าคลาสมีเพียงอินสแตนซ์เดียวและให้จุดเข้าถึงส่วนกลางแก่คลาสนั้น
รูปแบบ Singleton จำกัด จำนวนอินสแตนซ์ของวัตถุเฉพาะให้เป็นหนึ่งเดียว อินสแตนซ์เดียวนี้เรียกว่าซิงเกิล
วัตถุ Singleton ถูกนำมาใช้เป็นฟังก์ชั่นที่ไม่ระบุชื่อทันที ฟังก์ชั่นจะดำเนินการทันทีโดยใส่ในวงเล็บแล้วตามด้วยวงเล็บสองอันเพิ่มเติม มันถูกเรียกว่าไม่ระบุชื่อเพราะไม่มีชื่อ
โปรแกรมตัวอย่าง
var Singleton = (function () {
var instance;
function createInstance() {
var object = new Object("I am the instance");
return object;
}
return {
getInstance: function () {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
function run() {
var instance1 = Singleton.getInstance();
var instance2 = Singleton.getInstance();
alert("Same instance? " + (instance1 === instance2));
}
run()
Simplest / Cleanest สำหรับฉันหมายถึงเพียงแค่เข้าใจและไม่มีเสียงระฆังและเสียงดังที่ถูกกล่าวถึงในการอภิปรายเวอร์ชัน Java:
วิธีที่มีประสิทธิภาพในการใช้รูปแบบซิงเกิลใน Java คืออะไร?
คำตอบที่ตรงกับที่ง่ายที่สุด / สะอาดที่สุดในมุมมองของฉันคือ:
https://stackoverflow.com/a/70824/1497139
และสามารถแปลเป็น JavaScript ได้เพียงบางส่วนเท่านั้น ความแตกต่างบางประการใน Javascript คือ:
แต่ได้รับไวยากรณ์ ECMA ล่าสุดเป็นไปได้ที่จะเข้าใกล้:
รูปแบบซิงเกิลเป็นตัวอย่างคลาส JavaScript
class Singleton {
constructor(field1,field2) {
this.field1=field1;
this.field2=field2;
Singleton.instance=this;
}
static getInstance() {
if (!Singleton.instance) {
Singleton.instance=new Singleton('DefaultField1','DefaultField2');
}
return Singleton.instance;
}
}
ตัวอย่างการใช้งาน
console.log(Singleton.getInstance().field1);
console.log(Singleton.getInstance().field2);
ตัวอย่างผลลัพธ์
DefaultField1
DefaultField2
function Once() {
return this.constructor.instance || (this.constructor.instance = this);
}
function Application(name) {
let app = Once.call(this);
app.name = name;
return app;
}
หากคุณเข้าเรียน:
class Once {
constructor() {
return this.constructor.instance || (this.constructor.instance = this);
}
}
class Application extends Once {
constructor(name) {
super();
this.name = name;
}
}
ทดสอบ:
console.log(new Once() === new Once());
let app1 = new Application('Foobar');
let app2 = new Application('Barfoo');
console.log(app1 === app2);
console.log(app1.name); // Barfoo
ถ้าคุณต้องการใช้คลาส:
class Singleton {
constructor(name, age) {
this.name = name;
this.age = age;
if(this.constructor.instance)
return this.constructor.instance;
this.constructor.instance = this;
}
}
let x = new Singleton('s',1);
let y = new Singleton('k',2);
ผลลัพธ์สำหรับข้างต้นจะเป็น:
console.log(x.name,x.age,y.name,y.age) // s 1 s 1
อีกวิธีในการเขียน Singleton โดยใช้ฟังก์ชั่น
function AnotherSingleton (name,age) {
this.name = name;
this.age = age;
if(this.constructor.instance)
return this.constructor.instance;
this.constructor.instance = this;
}
let a = new AnotherSingleton('s',1);
let b = new AnotherSingleton('k',2);
ผลลัพธ์สำหรับข้างต้นจะเป็น:
console.log(a.name,a.age,b.name,b.age)// s 1 s 1