Javascript ES6单例vs一次实例化一个类

Javascript ES6单例vs一次实例化一个类,javascript,es6-class,Javascript,Es6 Class,我看到使用ES6类的单例模式的模式,我想知道为什么我会使用它们,而不是在文件底部实例化类并导出实例。这样做有什么负面的缺点吗?例如: ES6导出实例: import API from './services/api-service' 用法: import API from './services/api-service' 使用以下单例模式有什么区别?使用其中一个有什么原因吗?事实上,我更想知道我给出的第一个例子是否有我不知道的问题 单例模式: import API from './servi

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

ES6导出实例:

import API from './services/api-service'
用法:

import API from './services/api-service'
使用以下单例模式有什么区别?使用其中一个有什么原因吗?事实上,我更想知道我给出的第一个例子是否有我不知道的问题

单例模式:

import API from './services/api-service'
用法:

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

区别在于,如果你想测试东西

假设您有
api.spec.js
测试文件。您的API有一个依赖项,就像这些常量一样

具体地说,两个版本中的构造函数都采用一个参数,即
常量
导入

因此,您的构造函数如下所示:

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.
    });
});
现在,对于导出实例,没有模拟

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

导出实例化对象后,您无法(轻松而理智地)更改其行为。

我建议两者都不要。这完全过于复杂了。如果你只需要一个对象!去买吧

import Constants from '../constants';

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


使用单例模式的另一个原因是在某些框架中(如
Polymer 1.0
),您不能使用
export
语法。
这就是为什么第二个选项(单例模式)对我来说更有用的原因

希望能有所帮助。

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

const APIobj = new _API();
export default APIobj;   //shortcut=> export new _API()
然后在多个文件中像下面这样导入将指向同一个实例和创建单例模式的方法

import APIobj from './services/api-service'
然而,直接导出类的另一种方式并不像我们导入的文件中那样是单例的,我们需要重新创建类,这将为每个新创建创建一个单独的实例 仅导出类:

export default API;
导入类和更新

import API from './services/api-service';
let api = new API()

这是在jsp中实现这一点的正确、惯用的方法。请注意,javascript始终在语言中内置了单例。我们只是不称它们为单例,我们称它们为对象文本。因此,每当您需要一个对象的单个实例时,js程序员都会自动创建一个对象文本。在JS中,许多其他语言中的“设计模式”都是内置语法。如果你想把它作为依赖关系来获取,那么这是不合适的,所以更容易测试。@ C.SalalBelCA OP没有使用依赖注入,所以我没有考虑这个。你仍然不需要一个
,模块导入或工厂函数应足以使
fetch
可模拟。@答案中的代码部分解释了为什么单例对象应避免使用
class
语法。Javascript开发人员出于任何原因都倾向于通过导入硬编码其所有依赖项。我同意通过构造函数传递依赖项是更好的做法,这样它可以a)可测试,b)可重用。我给出这个答案是因为它实际上回答了我最初的问题。谢谢。”//呃……现在怎么办?“为什么不呢?API.url=MockConstants.API\u url;对象具有所有这些实例属性/方法,无论哪个类使用“this”进行访问。。但,突变当然会在单元中引起其他问题tests@ShishirArora问题在于这个。您有一个测试,其中断言
API.url==='example.com'
。一切都好。然后有人在测试之前插入这个
API.url==='something other'
——您正在修改整个测试套件的
API
对象,而不仅仅是一个测试实例。现在你破坏了其他测试——即使你没有(潜在地)破坏代码本身。这应该是所有测试套件中拆除操作的一部分。在开始一个新的测试之前,你应该清除测试留下的所有副作用。不过,平行化测试会是一个问题。
import APIobj from './services/api-service'
export default API;
import API from './services/api-service';
let api = new API()