ES6 Singleton vs Instantiating a Class once

2020-02-16 08:51发布

I see patterns which make use of a singleton pattern using ES6 classes and I am wondering why I would use them as opposed to just instantiating the class at the bottom of the file and exporting the instance. Is there some kind of negative drawback to doing this? For example:

ES6 Exporting Instance:

import Constants from '../constants';

class _API {
  constructor() {
    this.url = Constants.API_URL;
  }

  getCities() {
    return fetch(this.url, { method: 'get' })
      .then(response => response.json());
  }
}

const API = new _API();
export default API;

Usage:

import API from './services/api-service'

What is the difference from using the following Singleton pattern? Are there any reasons for using one from the other? Im actually more curious to know if the first example I gave can have issues that I am not aware of.

Singleton Pattern:

import Constants from '../constants';

let instance = null;

class API {
  constructor() {

    if(!instance){
      instance = this;
    }

    this.url = Constants.API_URL;

    return instance;
  }

  getCities() {
    return fetch(this.url, { method: 'get' })
      .then(response => response.json());
  }
}

export default API;

Usage:

import API from './services/api-service';

let api = new API()

5条回答
来,给爷笑一个
2楼-- · 2020-02-16 08:57

Another reason to use Singleton Pattern is in some frameworks (like Polymer 1.0) you can't use export syntax.
That's why second option (Singleton pattern) is more useful, for me.

Hope it helps.

查看更多
淡お忘
3楼-- · 2020-02-16 09:02

I would recommend neither. This is totally overcomplicated. If you only need one object, do not use the class syntax! Just go for

import Constants from '../constants';

export default {
  url: Constants.API_URL,
  getCities() {
    return fetch(this.url, { method: 'get' }).then(response => response.json());
  }
};

import API from './services/api-service'

or even simpler

import Constants from '../constants';

export const url = Constants.API_URL;
export function getCities() {
  return fetch(url, { method: 'get' }).then(response => response.json());
}

import * as API from './services/api-service'
查看更多
混吃等死
4楼-- · 2020-02-16 09:12

In addition to all the answers given, a class has the property of getting extended (inheritance). How possibly do you think you can let developers extend your class, if all you are exporting is a single instance from its module file?

查看更多
等我变得足够好
5楼-- · 2020-02-16 09:15

Both are different ways. Exporting a class like as below

const APIobj = new _API();
export default APIobj;   //shortcut=> export new _API()

and then importing like as below in multiple files would point to same instance and a way of creating Singleton pattern.

import APIobj from './services/api-service'

Whereas the other way of exporting the class directly is not singleton as in the file where we are importing we need to new up the class and this will create a separate instance for each newing up Exporting class only:

export default API;

Importing class and newing up

import API from './services/api-service';
let api = new API()
查看更多
倾城 Initia
6楼-- · 2020-02-16 09:19

The difference is if you want to test things.

Say you have api.spec.js test file. And that your API thingy has one dependency, like those Constants.

Specifically, constructor in both your versions takes one parameter, your Constants import.

So your constructor looks like this:

class API {
    constructor(constants) {
      this.API_URL = constants.API_URL;
    }
    ...
}



// single-instance method first
import API from './api';
describe('Single Instance', () => {
    it('should take Constants as parameter', () => {
        const mockConstants = {
            API_URL: "fake_url"
        }
        const api = new API(mockConstants); // all good, you provided mock here.
    });
});

Now, with exporting instance, there's no mocking.

import API from './api';
describe('Singleton', () => {
    it('should let us mock the constants somehow', () => {
        const mockConstants = {
            API_URL: "fake_url"
        }
        // erm... now what?
    });
});

With instantiated object exported, you can't (easily and sanely) change its behavior.

查看更多
登录 后发表回答