JavaScript에서 싱글 톤을 구현하는 가장 간단하고 깔끔한 방법은 무엇입니까?


300

JavaScript에서 싱글 톤 패턴을 구현하는 가장 간단하고 깨끗한 방법은 무엇입니까?


15
허용되는 답변에 대한 공감대가 전혀 싱글 톤이 아닙니다. 전역 변수 일뿐입니다.
mlibby

5
이것은 많은 정보이지만 실제로는 JS 디자인 패턴 간의 차이점을 설명합니다. 그것은 많은 도움이되었습니다 : addyosmani.com/resources/essentialjsdesignpatterns/book
Justin

답변:


315

가장 쉬운 방법은 간단한 객체 리터럴을 선언하는 것입니다.

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'
// ...

46
+1 전역 변수가있는 언어에서 "Singleton 패턴"을 찾는 것이 조금 이상하지 않습니까 ???
Victor

4
모듈 패턴을 사용하여 공개 멤버는 다른 공개 멤버에 어떻게 액세스합니까? 즉, 어떻게 publicMethod1전화 publicMethod2합니까?
typeof

4
@Tom, 예, 패턴은 클래스 기반 OOP 언어에서 태어났습니다. 정적 getInstance메소드와 개인 생성자를 포함한 많은 구현을 기억합니다 . 그러나 IMO는 싱글 톤 객체를 만드는 가장 "간단한"방법입니다. Javascript에서 마지막에는 동일한 목적을 달성합니다. 단일 객체는 다시 초기화 할 수 없습니다 (생성자가없고 객체 일뿐입니다). 링크 한 코드에 대해서는 몇 가지 문제가 a있으며 b변수 선언을 바꾸고 테스트하십시오 a === window. 건배.
CMS

15
@Victor – 이러한 언어에서 "단일 패턴"을 찾는 것은 이상하지 않습니다. 많은 객체 지향 언어가 전역 변수를 사용하고 여전히 싱글 톤이 사용되고 있습니다. Singleton은 주어진 클래스의 객체가 하나만 있다고 보장하지는 않습니다. Singleton에는 몇 가지 기능이 더 있습니다. 1) 처음 사용시 초기화되어야합니다 (초기화 지연을 의미 할뿐만 아니라 객체를 실제로 사용할 준비가되었음을 보장합니다) 2) 스레드로부터 안전해야합니다. 모듈 패턴은 싱글 톤 패턴을 대체 할 수 있지만 브라우저에서만 가능합니다 (항상 그런 것은 아님).
skalee

55
이것은 정답이 아니어야합니다. 이것은 전혀 싱글 톤이 아닙니다! 이것은 단지 전역 변수입니다. 둘 사이에는 차이가 있습니다.
mlibby

172

가장 깨끗한 접근 방식은 다음과 같습니다.

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();

4
비고 : 다음을 사용하여 원래 생성자를 다시 읽을 수 있습니다 delete instance.constructor.x = SingletonClass.getInstance();delete x.constructor;new x.constructor;
Rob W

var test = SingletonClass.getInstance ()-매우 깨끗하거나 JS처럼 보이지 않습니다. a = new Foo ();로 끝나는 다른 영혼. b = 새로운 Foo (); a === b // true
마티아스

3
전체 "getInstance"부분을 통해 팩토리와 같은 냄새가납니다.
Lajos Meszaros

1
Object.create를 사용하여 여러 인스턴스를 만들 수 있기 때문에 단일 항목이 아닙니다.
AndroidDev

바이올린이 고장
HoffZ

103

싱글 톤 패턴의 대체물로 사용되는 모듈 패턴에 동의하지 않습니다. 나는 종종 싱글 톤이 완전히 불필요한 곳에서 사용되고 남용되는 것을 보았으며, 프로그래머가 싱글 톤을 사용하는 모듈 패턴이 많은 간격을 메 우지 만 모듈 패턴은 싱글 톤 이 아닙니다 .

모듈 패턴 :

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

4
나는 싱글 톤이 나쁘거나 좋은 아이디어라고 결코 말하지 않았다. 싱글 톤 구현은 Java의 한계를 패턴을 전혀 이해하지 못하는 것처럼 혼동하기 때문에 필요한 것보다 훨씬 복잡하다고 말했다. Javascript에서 익명 함수를 간단하게 사용할 수있을 때 생성자 함수 및 메소드를 작성하여 전략 패턴을 구현하는 것과 같습니다.
Esailija

11
@Esailija, 싱글 톤 패턴을 이해하지 못하는 것처럼 들립니다. 싱글 톤 패턴은 클래스의 인스턴스화를 하나의 객체로 제한하는 디자인 패턴입니다. var singleton = {}그 정의에 맞지 않습니다.
zzzzBov

9
제한 사항 때문에 Java와 같은 언어에만 적용됩니다. var singleton = {}Javascript에서 싱글 톤을 구현하는 방법 입니다.
Esailija

2
@Esailija, "개체를 사용하지만 클래스는 사용하지 않는 프로토 타입 기반 프로그래밍 언어에서 ..."JavaScript에는 클래스 개념이 있으므로 적용되지 않습니다.
zzzzBov


18

에서 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

1
Singleton이 다른 클래스 주위를 감싸고 instance필드 만 있으면 얼리는 것이 합리적 입니다. 현재 (로 instance설정 됨 this)이 클래스에는 다른 필드도있을 수 있으며 동결은 의미가 없습니다.
thisismydesign

10

다음은 노드 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' }

8

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하고 _instance. 밑줄이 앞에 붙은 개인 변수의 이름을 지정하는 것은 프로그래밍 언어의 명명 규칙입니다 . 코드가 작동하지 않는 이유는 귀하가 this.instance대신 사용하고 있기 때문 입니다MyClass.instance
UtkarshPramodGupta

7

고양이를 피부에 바르는 방법은 여러 가지가 있습니다 :) 당신의 취향이나 특정한 필요에 따라 제안 된 솔루션을 적용 할 수 있습니다. 개인 정보가 필요하지 않은 경우 가능하면 CMS의 첫 번째 솔루션을 개인적으로 선택합니다. 질문이 가장 단순하고 깨끗하다는 것이 었으므로 이것이 승자입니다. 또는:

var myInstance = {}; // done!

이것은 (내 블로그에서 인용) ...

var SingletonClass = new function() { 
    this.myFunction() { 
        //do stuff 
    } 
    this.instance = 1; 
}

개인 var가 필요 없기 때문에 이해가되지 않습니다 (블로그 예제도 마찬가지입니다). 그래서 다음과 거의 같습니다.

var SingletonClass = { 
    myFunction: function () { 
        //do stuff 
    },
    instance: 1 
}

코드 스 니펫 2에 구문 오류가 있습니다. 글을 쓸 수 없습니다this.f(){}
xoxox

7

답변을 더 이상 사용하지 않습니다 . 다른 답변을 참조하십시오 .

일반적으로 싱글 톤 패턴이 아닌 모듈 패턴 (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

모듈이 필요하지 않은 이유는 무엇입니까? 모듈을로드해야 할 때 모듈을로드하면 초기화됩니다.
Esailija

6

짧은 답변:

JavaScript의 비 차단 특성으로 인해 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();
});

설명:

싱글 톤은 전체 애플리케이션을 통해 하나 이상의 인스턴스를 제공합니다. 초기화는 처음 사용할 때까지 지연됩니다. 초기화가 비싼 객체를 다룰 때 이것은 정말 큰 일입니다. 비용이 많이 드는 것은 일반적으로 I / O를 의미하며 JavaScript의 I / O는 항상 콜백을 의미합니다.

와 같은 인터페이스를 제공하는 답변을 믿지 마십시오 instance = singleton.getInstance(). 모두 요점을 놓칩니다.

인스턴스가 준비 될 때 콜백을 실행하지 않으면 초기화 프로그램이 I / O를 수행 할 때 작동하지 않습니다.

예, 콜백은 항상 객체 인스턴스를 즉시 반환하는 함수 호출보다 더 나빠 보입니다. 그러나 다시 : I / O를 수행 할 때 콜백은 필수입니다. I / O를 원하지 않는 경우 인스턴스화는 프로그램 시작시 수행하기에 충분히 저렴합니다.

예 1, 저렴한 이니셜 라이저 :

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);
});

예제 2, I / O로 초기화 :

이 예 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.");

잘라 내지 않은 다른 싱글 톤 답변을 사용한 시련과 환난을 통해 필자는 이와 비슷한 결과 코드를 얻었습니다.
mheyman

어떤 이유로 든, 이것은 나에게 이해되는 유일한 대답입니다. 다른 대답은 모두 세 명의 남자가 서로 어깨를 재귀 적으로 올라가서 벽에 4 명이 높이 올라 가려고하는 공연 쇼 에피소드를 떠올리게합니다.
Tim Ogilvy

콜백 스태킹은 내가 정말로 필요한 것입니다! 감사!!
Tim Ogilvy

이 접근법은 실제로 싱글 톤을 제공하지 않습니다 : singleton (singletonInitializer)! == singleton (singletonInitializer) 그들은 두 개의 다른 인스턴스입니다. 반환 된 결과 함수를 사용하여 인스턴스에 더 많은 콜백을 첨부 할 수 있지만이 유형의 인스턴스를 하나만 만들 수 있다고 엄격하게 지정하지는 않습니다. 이것은 싱글 톤의 요점입니다.
Owen

6

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 

이 접근법은 프로토 타입 확장을 사용할 때 (고정 될 수는 있지만 간단하지는 않지만) 개인 정적 구현이 실패하고 인스턴스로 인해 공개 정적 구현이 권장되지 않는 경우 모든 테스트 사례를 통과합니다.

jsFiddly 데모.


5

JavaScript로 프로그래밍하는 가장 깨끗한 방법을 찾았지만 상상력이 필요합니다. 이 아이디어는 "javascript the good parts"책의 작동 기술에서 얻었습니다.

새 키워드를 사용하는 대신 다음과 같은 클래스를 만들 수 있습니다.

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();

완전한 "클래스"에 액세스 할 수 없기 때문에 이것이 가장 쉬운 방법이라고 생각합니다.


그러나이 기술을 사용하면 둘 이상의 인스턴스를 가질 수 있습니다. 옳지 않다.
nicolascolman 2016 년

1
나는 그렇게 생각하지 않을 것입니다. getInstance를 거치지 않고 클래스에 액세스 할 수도 없습니다. 좀 더 자세히 설명해 주시겠습니까?
David

David Maes 죄송하지만 두 번째 예에서는 유효성 검사를 보지 못했습니다. 죄송합니다.
nicolascolman 2016

4

@CMS와 @zzzzBov는 훌륭한 답변을 주었지만 싱글 톤 패턴이 일반적인 PHP / Zend Framework에서 무거운 node.js 개발로 옮겨 간 것에 근거하여 내 자신의 해석을 추가하기 만하면됩니다.

다음 주석으로 작성된 코드는 다음 요구 사항을 기반으로합니다.

  • 함수 객체의 하나의 인스턴스 만 인스턴스화 될 수 있습니다.
  • 인스턴스는 공개적으로 사용할 수 없으며 공개 메소드를 통해서만 액세스 할 수 있습니다
  • 생성자는 공개적으로 사용할 수 없으며 사용 가능한 인스턴스가없는 경우에만 인스턴스화 할 수 있습니다
  • 생성자의 선언은 프로토 타입 체인을 수정해야합니다. 이를 통해 생성자는 다른 프로토 타입에서 상속하고 인스턴스에 대한 "공개"메소드를 제공 할 수 있습니다.

내 코드는 @zzzzBov와 매우 유사합니다. 제작자에 프로토 타입 체인을 추가했으며 PHP 또는 유사한 언어에서 온 사람들이 전통적인 OOP를 Javascripts 프로토 타입으로 변환하는 데 도움이되는 더 많은 주석을 추가했습니다. "가장 단순하지"는 않지만 가장 적절하다고 생각합니다.

// 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'

기술적으로, 자체 실행 익명 함수는 @CMS에서 제공 한 코드에서 잘 설명 된대로 자체적으로 싱글 톤입니다. 여기서 유일한 발견은 생성자 자체가 익명 인 경우 생성자의 프로토 타입 체인을 수정할 수 없다는 것입니다.

Javascript의 경우 "public"및 "private"개념은 PHP 또는 Java에서와 같이 적용되지 않습니다. 그러나 Javascript의 기능 범위 가용성 규칙을 활용하여 동일한 효과를 얻었습니다.


코드에서 여러 인스턴스를 만들 수 있습니다.var a = Singleton.getInstance('foo'); var b = new a.constructor('bar');
zzzzBov

@zzzzBov : 난 그냥 시도하고 오류를 받고 있어요 나의 바이올린의 : jsfiddle.net/rxMu8
cincodenada

4

아무도 이것을 제기하지 않은 이유는 확실하지 않지만 다음과 같이 할 수 있습니다.

var singleton = new (function() {
  var bar = 123

  this.foo = function() {
    // whatever
  }
})()

이것은 getInstance 메소드를 건너 뛰고보다 간단한 솔루션을 얻는 깔끔한 방법 인 것 같습니다. 그러나 싱글 톤은 파일이 구문 분석되는 즉시 실행되므로 DOM 리스너는 $ (document) .ready 함수로 랩핑되어야합니다.
HoffZ

4

가장 분명한 답은 Addy Osmani의 Learning JavaScript Design Patterns 책에서 나온 것입니다.

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;
    }
 
  };
 
})();


3

ES7이 필요하지만 가장 단순하고 깨끗하고 직관적 인 방법이라고 생각합니다.

export default class Singleton {

  static instance;

  constructor(){
    if(instance){
      return instance;
    }

    this.state = "duke";
    this.instance = this;
  }

}

소스 코드는 다음과 같습니다 : adam-bien.com


이것은 완전히 잘못 되었으며 호출시 오류가 발생 합니다new Singleton()
UtkarshPramodGupta

2

이게 뭐가 문제 야?

function Klass() {
   var instance = this;
   Klass = function () { return instance; }
}

Test = Klass; t1 = new Test(); t2 = new Test();-클래스 이름을 바꾸거나 다른 네임 스페이스를 선택할 기회가 없습니다.
zzzzBov

2

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)

2

new 연산자를 사용 하면 함수 내에서 이것을 즉시 사용할 수 있으므로 객체 리터럴을 반환 할 필요가 없기 때문에 다음이 가장 쉬운 Singleton 패턴이라는 것을 알았습니다 .

var singleton = new (function () {

  var private = "A private value";
  
  this.printSomething = function() {
      console.log(private);
  }
})();

singleton.printSomething();


2

다음은 자바 스크립트에서 싱글 톤 패턴을 설명하는 간단한 예입니다.

 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();

1

나는 몇 가지 싱글 톤이 필요했습니다.

  • 게으른 초기화
  • 초기 매개 변수

그래서 이것은 내가 생각해 낸 것입니다.

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;
}
  • 빈 변수가 있으면 [] 만 전달하면됩니다.

  • 함수에서 창 객체를 사용했지만 매개 변수를 전달하여 자체 범위를 만들 수있었습니다.

  • name 및 construct 매개 변수는 window []가 작동하기위한 문자열 일 뿐이며 간단한 유형 검사를 통해 window.name 및 window.construct도 가능합니다.


1

이런 식으로 수업을 다시 시작할 수 없도록하십시오.

이를 통해 instanceofop를 사용할 수 있으며 프로토 타입 체인을 사용하여 클래스를 상속 할 수 있습니다. 일반 클래스이지만 인스턴스를 사용하려는 경우 새 클래스를 사용할 수 없습니다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멤버 를 노출시키지 않으려면 멤버를 클로저에 넣으십시오.


1

다음은 싱글 톤 패턴을 구현하기 위해 걷는 스 니펫입니다. 이것은 인터뷰 과정에서 나에게 일어 났고 나는 이것을 어딘가에 포착해야한다고 느꼈다.

/*************************************************
   *     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
  *******************************************************************/

요지 페이지 에서도 마찬가지입니다 .


1
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

1

이것도 싱글 톤 아닌가요?

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();

1

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 런타임에 데코레이터가 실제로 활성화되어 있는지 확인하거나 Babel 및 TypeScript와 같은 컴파일러를 사용해야합니다.

또한 싱글 톤 인스턴스는 "lazy"로 작성됩니다. 즉, 처음 사용할 때만 작성됩니다.


1

모듈 패턴 : "더 읽기 쉬운 스타일" 어떤 방법이 공개인지, 어떤 방법이 비공개인지 쉽게 볼 수 있습니다

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 (); //-> 공개 메소드 알림 ( "hi im a private method")을 통해 비공개 메소드를 호출하고 있습니다.

http://jsfiddle.net/ncubica/xMwS9/


1

하나씩 일어나는 것:

클래스에 인스턴스가 하나만 있는지 확인하고 글로벌 액세스 지점을 제공하십시오.

싱글 톤 패턴은 특정 객체의 인스턴스 수를 하나로 제한합니다. 이 단일 인스턴스를 싱글 톤이라고합니다.

  • 고유 인스턴스를 리턴하는 getInstance ()를 정의합니다.
  • 인스턴스 객체 생성 및 관리를 담당합니다.

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()


1

나를 위해 가장 단순하고 깨끗하다는 것은 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

1
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

1

클래스를 사용하려는 경우 :

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

함수를 사용하여 싱글 톤을 작성하는 다른 방법

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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.