在Typescript/ES6中,Singleton模式的正确方法是什么?

Har*_*dhi 4 javascript typescript ecmascript-6

class Foo{

}

var instance: Foo;
export function getFooInstance(){
    /* logic */
}
Run Code Online (Sandbox Code Playgroud)

要么

export class Foo{
    private static _instance;
    private constructor(){};
    public getInstance(){/* logic */}
}

// Use it like this
Foo.getInstance()
Run Code Online (Sandbox Code Playgroud)

我想确保对象只有一个方法实例?除此之外的任何其他建议?

Typescript Playground 链接:

Nit*_*mer 5

如果你想在类中使用getter,那么它需要是静态的:

export class Foo{
    private static _instance;
    private constructor(){};
    public static getInstance(){/* logic */}
}
Run Code Online (Sandbox Code Playgroud)

问题在于,虽然编译器将强制执行此私有可见性,但在运行时仍然可以绕过它,甚至是无意中,例如有人直接使用javascript.

如果使用模块/命名空间强制执行它,则可以完全隐藏它:

使用模块:

export interface IFoo {}

class Foo implements IFoo {}

var instance: Foo;
export function getFooInstance(): IFoo {
    /* logic */

    return instance;
}
Run Code Online (Sandbox Code Playgroud)

这是你的代码,我只是对IFoo界面进行了修改(也是导出的),这样谁得到一个实例就会知道界面而不是类.

使用命名空间:

namespace Foo {
    export interface IFoo {}

    class FooClass implements IFoo {}

    const instance = new FooClass();
    export function getInstance(): IFoo {
        return instance;
    }
}
Run Code Online (Sandbox Code Playgroud)


pbo*_*pbo 5

在JS中,因此在TypeScript中,如果您真的只想要一个实例,为什么不通过仅导出对象文字来强制使用语言本身呢?

const Foo = {
  doSomething() {

  }
}

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

IMO,这是紧随KISS之后的事,最少的样板,任何人都无法创建多个实例。

话虽如此,您也可以直接导出函数。请记住,模块本身可以为您服务。

export function doSomething() {
}
Run Code Online (Sandbox Code Playgroud)

然后导入并想将其视为对象,可以使用import *。如果函数确实属于对象并且不是所有无状态静态函数,则我更喜欢第一种方法。

import * as Foo from './Foo';

Foo.doSomething();
Run Code Online (Sandbox Code Playgroud)

  • 如果我在不同的文件中多次导入 Foo 它们都会引用同一个对象? (3认同)