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 () {
}
};
})();
이를 모듈 패턴 이라고 하며 , 기본적으로 클로저를 사용하여 객체에 개인 멤버를 캡슐화 할 수 있습니다 .
업데이트 : 싱글 톤 객체의 수정을 방지 하려면 ES5 방법을 사용하여 고정 할 수 있다고 덧붙이고 싶습니다 Object.freeze
.
그러면 객체가 불변이되어 구조와 값이 수정되지 않습니다.
또한 ES6을 사용하는 경우 ES 모듈을 사용하여 싱글 톤을 매우 쉽게 나타낼 수 있으며 모듈 범위 에서 변수를 선언하여 개인 상태 를 유지할 수도 있습니다 .
// my-singleton.js
const somePrivateState = []
function privateFn () {
// ...
}
export default {
method1() {
// ...
},
method2() {
// ...
}
}
그런 다음 싱글 톤 객체를 가져 와서 사용할 수 있습니다.
import myInstance from './my-singleton.js'
// ...
답변
가장 깨끗한 접근 방식은 다음과 같습니다.
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();
답변
싱글 톤 패턴의 대체물로 사용되는 모듈 패턴에 동의하지 않습니다. 나는 종종 싱글 톤이 완전히 불필요한 곳에서 사용되고 남용되는 것을 보았으며, 프로그래머가 싱글 톤을 사용하는 모듈 패턴이 많은 간격을 메 우지 만 모듈 패턴은 싱글 톤 이 아닙니다 .
모듈 패턴 :
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;
}());
내가 제공 한 Singleton 패턴의 두 버전 모두에서 생성자 자체를 접근 자로 사용할 수 있습니다.
var a,
b;
a = new Foo(); //constructor initialization happens here
b = new Foo();
console.log(a === b); //true
이런 식으로 생성자를 사용하는 것이 불편하다면 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
답변
에서 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
답변
다음은 노드 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"
답변
고양이를 피부에 바르는 방법은 여러 가지가 있습니다 🙂 당신의 취향이나 특정한 필요에 따라 제안 된 솔루션을 적용 할 수 있습니다. 개인 정보가 필요하지 않은 경우 가능하면 CMS의 첫 번째 솔루션을 개인적으로 선택합니다. 질문이 가장 단순하고 깨끗하다는 것이 었으므로 이것이 승자입니다. 또는:
var myInstance = {}; // done!
이것은 (내 블로그에서 인용) …
var SingletonClass = new function() {
this.myFunction() {
//do stuff
}
this.instance = 1;
}
개인 var가 필요 없기 때문에 이해가되지 않습니다 (블로그 예제도 마찬가지입니다). 그래서 다음과 거의 같습니다.
var SingletonClass = {
myFunction: function () {
//do stuff
},
instance: 1
}