[javascript] 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 () {
    }
  };
})();

이를 모듈 패턴 이라고 하며 , 기본적으로 클로저를 사용하여 객체에 개인 멤버를 캡슐화 할 수 있습니다 .

업데이트 : 싱글 톤 객체의 수정을 방지 하려면 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
}