代码之家  ›  专栏  ›  技术社区  ›  Amit Wagner

扩展es6中的singleton类

  •  1
  • Amit Wagner  · 技术社区  · 6 年前

    我所面临的问题是,我得到的是从中扩展的类实例,而不是只得到类的方法。

    super 无法获取实例,但我出现了一个错误

    在访问“this”或从派生构造函数返回之前,必须在派生类中调用超级构造函数

    代码示例:

    let instanceA = null;
    let instanceB = null;
    
    class A {
      constructor(options) {
        if (instanceA === null) {
          this.options = options;
          instanceA = this;
        }
        return instanceA;
      }
    }
    
    class B extends A {
      constructor(options) {
        if (instanceB === null) {
          super()
          console.log('real class is ' + this.constructor.name)
          this.options = options
          instanceB = this;
        }
        return instanceB;
      }
    }
    
    const a = new A({
      i_am_a: "aaaaaa"
    });
    
    const b = new B({
      i_am_b: "bbbbbb"
    }) // this change a 
    
    console.log(b.options)
    
    console.log(a.options)
    3 回复  |  直到 6 年前
        1
  •  2
  •   FK82    6 年前

    首先,这里有一个误解:

    我试图删除超级不得到实例,但后来我得到了一个错误

    super() 调用父类的 在创建的子类实例上(即 this 正在引用)。它不返回父类实例。 See here 更多信息。

    超级() 完全不违反父类的singleton属性。如果实现正确,很可能只构造一次。


    考虑到这一点,您应该稍微改进一下代码。

    静态构造函数 如果不存在实例,则创建singleton,或者返回创建的实例。

    SO answer 支持Java单例的这一点。

    带有静态构造函数且没有参数的完整示例如下所示:

    let instanceA = null;
    let instanceB = null;
    
    let counters = { A: 0, B: 0 }; // count class instantiations
    
    class A {
      static getInstance() {
        if (instanceA === null) {
          instanceA = new A();
        }
        return instanceA;
      }
      whoami() {
        const name = this.constructor.name;
        return `${name} #${counters[name]}`;
      }
      constructor() {
        counters[this.constructor.name] += 1;
      }
    }
    
    class B extends A {
      static getInstance() {
        if (instanceB === null) {
          instanceB = new B();
        }
        return instanceB;
      }
      constructor() {
        super();
      }
    }
    
    const a1 = A.getInstance();
    const a2 = A.getInstance();
    const a3 = A.getInstance();
    const b1 = B.getInstance();
    const b2 = B.getInstance();
    const b3 = B.getInstance();
    console.log(a1.whoami());
    console.log(a2.whoami());
    console.log(a3.whoami());
    console.log(b1.whoami());
    console.log(b2.whoami());
    console.log(b3.whoami());

    请注意 B 继承 whoami A

    显然,使用这种方法,除非只使用静态构造函数来生成实例(因为构造函数仍然是可访问的),否则不能保证singleton属性适用于每个类。不过,我认为这是一个很好的妥协。

        2
  •  1
  •   James Long    6 年前

    在JavaScript中,singleton只是一个对象文本。

    const a = {
        options: {
            i_am_a: "aaaaaa"
        }
    };
    const b = {
        options: {
            i_am_b: "bbbbbb"
        }
    };
    

    如果你真的需要一个构造函数,你可以写一个返回一个对象的函数。

    function makeSingleton(options) {
    
        return {
            options
        }
    
    }
    
    const a = makeSingleton({i_am_a: "aaaaaa"});
    const b = makeSingleton({i_am_b: "bbbbbb"});
    

    这里没有继承链,只有两个对象文本。如果你真的需要一个类,你可以创建一个,但这是一个不必要的浪费资源和打字。

    class Singleton {
    
        constructor(options) {
            this.options = options;
        }
    
    }
    
    const a = new Singleton({i_am_a: "aaaaaa"});
    const b = new Singleton({i_am_b: "bbbbbb"});
    

    Object.create() Object.assign() ,取决于您的需要。请注意,这两个都是浅-他们只工作一层深,所以修改孩子的眼睛 options 属性将修改父对象的 财产也是。

    const a = {
        options: {
            i_am_a: "aaaaaa"
        },
        getOptions() {
            return this.options;
        }
    };
    const b = Object.create(a);
    b.options.i_am_b: "bbbbbb";
    a.options.i_am_b; // -> "bbbbbb"
    b.getOptions(); // -> { i_am_a: "aaaaaa", i_am_b: "bbbbbb" }
    

    当然,你可以用 对象.创建() 选项 也。

    老实说,我认为您要么需要同一类的两个实例,要么需要一个没有任何继承的简单对象文本。

        3
  •  0
  •   Amit Wagner    6 年前

    我不知道这是否是最好的解决方案,但我所做的是检查构造函数名是否与类名不同。如果是这样的话,我就让它创建一个新实例,因为这意味着我要扩展这个类

    下面是我的测试的一个工作示例

    let instanceA = null;
    let instanceB = null;
    
    class A {
      constructor(options) {
        this.options = options;
      	
        if (instanceA === null) {
         
          	instanceA = this;
        }
        if(this.constructor.name !== "A"){
        	return this;
        }
        
        return instanceA;
      }
      
      method1(){
        console.log(this.constructor.name)
      }
    }
    
    class B extends A {
      constructor(options) {
        if (instanceB === null) {
          super(options)
          instanceB = this;
        }
        return instanceB;
      }
    }
    
    const a = new A({
      i_am_a: "aaaaaa"
    });a
    
    const b = new B({
      i_am_b: "bbbbbb"
    }) 
    const c = new A({
      i_am_c: "ccccc"
    });
    const d = new B({
      i_am_d: "ddddd"
    }) 
    console.log(a.options)
    console.log(b.options)
    console.log(c.options)
    console.log(d.options)
    a.method1();
    b.method1();
    c.method1();
    d.method1();
        4
  •  0
  •   алексей хмилевой    3 年前

    const instances = {}
    
    class Singleton {
        constructor() {
            const instance = instances[this.constructor];
    
            if (instance == null) {
                return instances[this.constructor] = this;
            }
    
            return instance;
        }
    }
    
    class Foo extends Singleton {
        constructor() {
            super();
    
            this.foo = "foo";
        }
    }
    
    class Bar extends Singleton {
        constructor() {
            super();
    
            this.foo = "bar";
        }
    }
    
    const foo1 = new Foo();
    const foo2 = new Foo();
    const bar1 = new Bar();
    const bar2 = new Bar();
    
    console.log(foo1 === foo2, bar1 === bar2, foo1 === bar1, foo1.foo = 123, foo2, bar1);