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.
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); // trueIn 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.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.