Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript Typescript/ES6中的单例模式的正确方式是什么?_Javascript_Typescript_Ecmascript 6 - Fatal编程技术网

Javascript Typescript/ES6中的单例模式的正确方式是什么?

Javascript Typescript/ES6中的单例模式的正确方式是什么?,javascript,typescript,ecmascript-6,Javascript,Typescript,Ecmascript 6,或 我想确保对象只有一个单向实例?除此之外还有其他建议吗 为两者键入脚本:如果要在类中使用getter,则它需要是静态的: export class Foo{ private static _instance; private constructor(){}; public getInstance(){/* logic */} } // Use it like this Foo.getInstance() 问题是,虽然编译器将强制实现这种私有可见性,但在运行时,即使是

我想确保对象只有一个单向实例?除此之外还有其他建议吗


为两者键入脚本:

如果要在类中使用getter,则它需要是静态的:

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

// Use it like this
Foo.getInstance()
问题是,虽然编译器将强制实现这种私有可见性,但在运行时,即使是无意中,如果有人直接从javascript使用它,仍然有可能绕过它

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

使用模块:

export class Foo{
    private static _instance;
    private constructor(){};
    public static getInstance(){/* logic */}
}
这是您的代码,我刚刚添加了
IFoo
接口(它也被导出),以便获得实例的人知道接口,但不知道类

使用命名空间:

export interface IFoo {}

class Foo implements IFoo {}

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

    return instance;
}

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

namespace Foo {
    export interface IFoo {}

    class FooClass implements IFoo {}

    const instance = new FooClass();
    export function getInstance(): IFoo {
        return instance;
    }
}
依我看,这是继KISS之后的,最少的样板文件,任何人都无法创建多个实例

也就是说,您也可以直接导出函数。请记住,模块本身可以作为您的单例

const Foo = {
  doSomething() {

  }
}

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

export function doSomething() {
}

这取决于是否有机会为singleton类创建新实例。在最后一种情况下,可以省略
getInstance
,类构造函数可以充当单例工厂:

import * as Foo from './Foo';

Foo.doSomething();
对于任何任意类,都可以使用decorator执行相同的操作,例如:

class Foo {
    private static _instance;
    constructor(...args) {
        if (Foo._instance) {
            return Foo._instance;
        }

        // if Foo extends non-singleton class or whatever,
        // super(...args);

        Foo._instance = this;
    };
}
由于存在一些,因此应该在
singleton
decorator中使用自定义继承代码,而不是
singleton扩展类

@singleton
class Foo { ... }
函数单例(类){
功能扩展(sub、sup){
用于(辅助中的var prop)
if(辅助hasOwnProperty(道具))
sub[prop]=sup[prop];
函数{
this.constructor=sub;
}
__.原型=辅助原型;
sub.prototype=新的;
};
常量单例=函数(…参数){
if(单例){
返回Singleton.\u实例;
}
类。应用(本,args);
Singleton.\u instance=this;
}
扩展(单例,类);
返回单身;
}

这可能会影响键入,但语法保持整洁。

旁注:JavaScript实际上不允许对实例实施限制。由于继承是在对象(原型)之间,而不是在类之间,因此始终可以创建第二个实例–
var second=Object.create(Object.getPrototypeOf(singleton))。不过,是的,这比
new Foo()
更麻烦。谢谢。这就是我要找的。如果我在不同的文件中多次导入Foo,它们都会引用相同的对象吗?
@singleton
class Foo { ... }
function singleton(Class) {
    function extend(sub, sup) {

        for (var prop in sup)
            if (sup.hasOwnProperty(prop))
                sub[prop] = sup[prop];

        function __() {
            this.constructor = sub;
        }

        __.prototype = sup.prototype;
        sub.prototype = new __();
    };

    const Singleton = <any>function (...args) {
        if (Singleton._instance) {
            return Singleton._instance;
        }

        Class.apply(this, args);

        Singleton._instance = this;
    }

    extend(Singleton, Class);

    return Singleton;
}