ES6 Singleton vs实例化一次类

Aar*_*ron 36 javascript es6-class

我看到使用ES6类使用单例模式的模式,我想知道为什么我会使用它们而不是仅仅在文件底部实例化类并导出实例.这样做有什么负面的缺点吗?例如:

ES6导出实例:

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;
Run Code Online (Sandbox Code Playgroud)

用法:

import API from './services/api-service'
Run Code Online (Sandbox Code Playgroud)

使用以下Singleton模式有什么区别?是否有任何理由使用另一个?我真的更好奇,知道我给出的第一个例子是否会有我不知道的问题.

单身模式:

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;
Run Code Online (Sandbox Code Playgroud)

用法:

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

let api = new API()
Run Code Online (Sandbox Code Playgroud)

Ber*_*rgi 34

我也不推荐.这完全过于复杂.如果您只需要一个对象,请不要使用class语法!只是去

import Constants from '../constants';

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

import API from './services/api-service'
Run Code Online (Sandbox Code Playgroud)

或者更简单

import Constants from '../constants';

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

import * as API from './services/api-service'
Run Code Online (Sandbox Code Playgroud)

  • 请注意,javascript一直都有内置于该语言的单例.我们只是不称他们为单身人士,我们称他们为对象文字.因此,只要您需要一个对象的单个实例,程序员就会自动创建一个对象文字.在js中,很多其他语言中的"设计模式"都是内置语法. (10认同)
  • 这是在js中执行此操作的正确,惯用方法 (3认同)
  • @codewise 答案中的[链接](/sf/ask/2711764961/)解释了为什么单例对象应避免使用“class”语法。 (3认同)

Zla*_*tko 15

不同之处在于你是否想要测试.

假设你有api.spec.js测试文件.并且你的API thingy有一个依赖,就像那些常量.

具体来说,两个版本中的构造函数都有一个参数,即Constants导入.

所以你的构造函数看起来像这样:

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.
    });
});
Run Code Online (Sandbox Code Playgroud)

现在,通过导出实例,没有嘲弄.

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

在导出实例化对象的情况下,您无法(轻松且理智地)更改其行为.

  • 不论出于何种原因,JavaScript开发人员都倾向于通过导入对所有依赖项进行硬编码。我同意,最好的做法是通过构造函数传递依赖项,以便a)可测试,b)可重用。 (2认同)
  • 我授予这个答案是因为它实际上回答了我最初的问题。谢谢。 (2认同)

Sum*_*mer 8

两者都是不同的方式。导出如下所示的类

const APIobj = new _API();
export default APIobj;   //shortcut=> export new _API()
Run Code Online (Sandbox Code Playgroud)

然后在多个文件中像下面这样导入将指向相同的实例和创建单例模式的方法。

import APIobj from './services/api-service'
Run Code Online (Sandbox Code Playgroud)

而另一种直接导出类的方式不是单例,因为在我们导入的文件中,我们需要新建类,这将为每个新建的导出类创建一个单独的实例:

export default API;
Run Code Online (Sandbox Code Playgroud)

导入类并更新

import API from './services/api-service';
let api = new API()
Run Code Online (Sandbox Code Playgroud)