J'essaie de faire mon implémentation du modèle singleton dans la classe JS ES6. Voici ce que j'ai écrit jusqu'à présent:

let instance;

export class TestClass{

    constructor(){
        if(new.target){
            throw new Error(`Can't create instance of singleton class with new keyword. Use getInstance() static method instead`);
        }
    }
    testMethod(){
        console.log('test');
    }
    static getInstance(){
        if(!instance) {
            instance = TestClass.constructor();
        }

        return instance;
    }
}

Cependant, lorsque j'appelle une méthode statique TestClass.getInstance(), je ne reçois pas d'instance d'objet de classe, je reçois

ƒ anonymous() {

}

Sans accès à testMethod. Je ne trouve pas d'erreur dans mon code - l'aide sera grandement appréciée.

4
Furman 15 avril 2018 à 23:30

3 réponses

Meilleure réponse

TestClass est la fonction constructeur. TestClass.constructor est le Function intégré qui, lorsqu'il est appelé, construit une nouvelle fonction vide (ce que vous enregistrez).

Le constructeur TestClass est également accessible en tant que TestClass.prototype.constructor, c'est ce que vous vouliez probablement dire:

static getInstance(){
    if (!instance) {
        instance = TestClass.prototype.constructor();
    }
    return instance;
}

Bien sûr, cela lèvera une exception que vous ne pouvez pas appeler des constructeurs class sans new.

Vous devez également simplifier en new TestClass. Ou encore mieux, si vous souhaitez prendre en charge le sous-classement, new this - notez que this dans la méthode statique fait référence à la classe (constructeur) elle-même.

J'essaie de faire mon implémentation de motif singleton dans la classe JS ES6

S'il vous plait, ne le faites pas. Les singletons sont une mauvaise pratique. Si votre classe n'a pas d'état et qu'il n'y a qu'une seule instance de toute façon, n'utilisez pas de class . Ecrivez

export function testMethod() {
    console.log('test');
}
// Yes, that's the whole file!

Si vous insistez pour construire paresseusement le module, je recommanderais

let instance;
/*default*/ export function getInstance() {
    return instance || (instance = { // use a simple object literal
        testMethod(){
            console.log('test');
        }
    });
}

Cela dit, si vous insistez pour créer un constructeur "privé", je passerais un jeton:

const internal = Symbol("creation token for TestClass");
export class TestClass {
    constructor(token) {
        if(token !== internal) {
            throw new Error("Please use the TestClass.getInstance() static method instead");
        }
    }
    …
    static getInstance(){
        return new TestClass(internal); // make sure not to call `this`, otherwise subclassing could leak the token
    }
}

Mais vous ne devriez jamais vraiment en avoir besoin.

3
Bergi 15 avril 2018 à 21:18

Vous n'avez pas créé d'instance de TestClass, vous venez d'affecter votre variable instance en tant que fonction constructeur de TestClass.

Je crée généralement le singleton comme ceci si je dois:

class TestClass {
  constructor() {

  }

  testMethod() {

  }
}

const instance = new TestClass();

export default instance;
0
Dan D 15 avril 2018 à 20:36

Le problème est que ES6 Class constructors cannot be invoked without 'new' - votre test new.target est superflu. Si vous souhaitez conserver votre syntaxe de classe, vous pouvez faire quelque chose comme ceci pour vous assurer que seul votre module a la capacité de créer la classe:

let instance;
let creating = false;
class TestClass{
  constructor(key) {
    if(!creating) {
      throw new Error(`Can't create instance of singleton class with new keyword. Use getInstance() static method instead`);
    }
  }
  testMethod() {
    console.log('test');
  }
  static getInstance() {
    if(!instance) {
      creating = true;
      instance = new TestClass();
      creating = false;
    }
    return instance;
  }
}

const theInst = TestClass.getInstance();
theInst.testMethod();
1
CertainPerformance 15 avril 2018 à 20:46