要获取想只能获取一次实体对象,我们需要在new 构造函数的时候跳出本次new的过程,要跳出此次的new过程,我们需要一个函数变量去缓存上一次new的实体对象,用于判断构造函数已经new过。
- // 生命instance变量缓存已new过的实体
- let instance = null;
- const createSingleton = function (name) {
- // 如果已经new过的跳出并返回缓存的实体,始终保持一个实体
- if (instance) return instance;
- this.name = name;
- instance = this; // 第一次new把实体返回
- return instance;
- }
- createInstance.prototype.getname = function () {
- console.log(this.name)
- };
- const a = new createSingleton ('aaa');
- const b = new createSingleton ('bbb');
- a.getname(); // aaa
- b.getname(); // aaa
生命一个instance变量用于保存第一次new出来的实体对象,在构造函数原型上写一个getname的方法获取name的值。构造函数里判断构造函数是否已经实例化过,然后跳出并返回第一次的实体对象。这种写法有种缺陷,那就是会多出一个外部变量,可能会污染到全局的某个变量的,所以我使用闭包去解决这种问题。
- // IIFE执行函数返回匿名函数当作构造函数,并利用闭包缓存实例化对象
- const createInstance = (
- function () {
- let instance = null;
- return function (name) {
- // 非第一次实例化跳出并返回第一次实体化对象
- if (instance) return instance;
- this.name = name;
- instance = this;
- return instance;
- }
- }
- )();
我们使用IIFE执行匿名函数,匿名函数里声明一个instance变量去缓存第一次实例化的对象,最后返回一个匿名函数当作构造函数。构造函数里利用instance去判断跳出此次实体化过程,在这个匿名函数里我们使用了闭包,所以我们在多次对这个构造函数实体化时,这个变量始终是第一次缓存下来的那个对象。
es6的类构造函数在类里面的constructor里,是个比较类似java类的一个类,所以我们可以在类里面写一个static的方法来获取这个类的实体(static是静态成员变量,可以让类不需要实例化就可以通过类去调用这个方法),并且做一些相应的判断去判断是否跳出并返回第一次的实体。
- class Singleton {
- constructor(name) {
- this.name = name;
- this.instance = null;
- }
- // 构造一个广为人知的接口,供用户对该类进行实例化
- static getInstance(name) {
- if(!this.instance) {
- this.instance = new Singleton(name);
- }
- return this.instance;
- }
- getName () {
- console.log(this.name);
- }
- }
- Singleton.getInstance('aaaa').getName()
- Singleton.getInstance('bbbb').getName()
在Singletom类的构造函数里同样写一个instance缓存第一次实体化类的对象,同时还有static方法getInstance获取实体化类的对象。getInstance方法用到this.instance去判断是否已经实体化过该类跳出返回实体类,否则实体化这个类。