Frontend Development 11 min read

Understanding the Singleton Pattern in JavaScript: Concepts, Implementations, and Real‑World Applications

This article explains the singleton design pattern, shows standard and lazy implementations in JavaScript with code examples, discusses reducing global variable pollution, and demonstrates practical usage in popular front‑end libraries such as Vuex, Ant Design message, and Axios request cancellation.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Understanding the Singleton Pattern in JavaScript: Concepts, Implementations, and Real‑World Applications

The singleton pattern ensures that a class has only one instance and provides a global access point, a concept widely used in front‑end development to avoid unnecessary object creation and reduce memory overhead.

Standard Singleton Example

var Singleton = function(name) {
    this.name = name;
    this.instance = null;
};

Singleton.prototype.getName = function() {
    alert(this.name);
};

Singleton.getInstance = function(name) {
    if (!this.instance) {
        this.instance = new Singleton(name);
    }
    return this.instance;
};

var a = Singleton.getInstance('sven1');
var b = Singleton.getInstance('sven2');
alert(a === b); // true

In JavaScript, a simple global variable can act like a singleton, but it does not guarantee immutability; therefore, encapsulating the instance inside a function or closure is preferred.

Reducing Global Variable Pollution

Use a namespace object to group related functions and variables.

Encapsulate private data with closures.

var namespace1 = {
    a: function() {},
    b: function() {}
};

var user = (function() {
    var _name = 'seven',
        _age = 29;
    return {
        getUserInfo: function() {
            return _name + '-' + _age;
        }
    };
})();

Lazy Singleton creates the instance only when it is first needed. A generic lazy‑singleton helper can be written as:

// Generic lazy singleton
var getSingle = function(fn) {
    var result;
    return function() {
        return result || (result = fn.apply(this, arguments));
    };
};

var createLoginLayer = function() {
    var div = document.createElement('div');
    div.innerHTML = '登录弹窗';
    div.style.display = 'none';
    document.body.appendChild(div);
    return div;
};

var createSingleLoginLayer = getSingle(createLoginLayer);

document.getElementById('loginBtn').onclick = function() {
    var loginLayer = createSingleLoginLayer();
    loginLayer.style.display = 'block';
};

Real‑World Applications

Vuex uses a singleton to ensure the store is installed only once:

let Vue;
export class Store {
    constructor(options = {}) {
        if (!Vue && typeof window !== 'undefined' && window.Vue) {
            install(window.Vue);
        }
    }
}

export function install(_Vue) {
    if (Vue && _Vue === Vue) {
        if (__DEV__) {
            console.error('[vuex] already installed. Vue.use(Vuex) should be called only once.');
        }
        return;
    }
    Vue = _Vue;
    applyMixin(Vue);
}

The Ant Design message component also follows a singleton approach by reusing a single messageInstance :

let messageInstance;
function getMessageInstance(callback) {
    if (messageInstance) {
        callback(messageInstance);
        return;
    }
    Notification.newInstance({
        prefixCls,
        transitionName,
        style: { top: defaultTop },
        getContainer,
        maxCount,
    }, instance => {
        if (messageInstance) {
            callback(messageInstance);
            return;
        }
        messageInstance = instance;
        callback(instance);
    });
}

Finally, a practical example shows how to cancel duplicate Axios requests by storing cancel tokens in a singleton‑like array, ensuring only the latest request for a given URL is active:

import axios from "axios";
const CancelToken = axios.CancelToken;
let cancelId = 0;
let cancelArray = [];

axios.interceptors.request.use(function(config) {
    const source = CancelToken.source();
    cancelId++;
    const id = cancelId;
    config.cancelId = id;
    config.cancelToken = source.token;
    const cancelIndex = cancelArray.findIndex(e => e.url === config.url);
    cancelArray.push({ id, url: config.url, source });
    if (cancelIndex > -1) {
        cancelArray[cancelIndex].source.cancel('Cancel duplicate request');
        cancelArray.splice(cancelIndex, 1);
    }
    return config;
}, function(error) { return Promise.reject(error); });

axios.interceptors.response.use(function(response) {
    const cancelIndex = cancelArray.findIndex(e => e.id === response.cancelId);
    if (cancelIndex >= 0) {
        cancelArray.splice(cancelIndex, 1);
    }
    return response;
}, function(error) {
    if (axios.isCancel(error)) {
        console.log('isCancel');
    } else {
        return Promise.reject(error);
    }
});

export default axios;

In summary, the singleton pattern—especially its lazy variant—is a fundamental and practical design technique in front‑end development, helping to manage global resources efficiently while adhering to the single‑responsibility principle.

frontendJavaScriptaxiosDesign PatternsingletonvuexLazy Initialization
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.