好处
可以减少不必要的内存开销,并且在减少全局的函数和变量冲突也具有重
要的意义
神不知鬼不觉的应用了单例模式(对象字面量创建对象)
let timeTool = {
name: '处理时间工具库',
getISODate: function() {},
getUTCDate: function() {}
}
这种字面量定义的对象,可以用于
管理模块
var devA = (function(){
//ajax模块
var ajax = {
get: function(api, obj) {console.log('ajax get调用')},
post: function(api, obj) {}
}
//dom模块
var dom = {
get: function() {},
create: function() {}
}
//event模块
var event = {
add: function() {},
remove: function() {}
}
return {
ajax: ajax,
dom: dom,
event: event
}
})()
这样可以防止全局变量重复的定义。开发好维护。
function xxx1(){}
function xxx2(){}
function xxx3(){}
如果这样定义一大堆全局的方法,属性,这样会对全局空间的一种污染,一旦项目中取了同样的名字,那么就容易出现问题
如果需要有一些私有变量和私有方法的时候,此时的对象字面创建单例就行不通了,我们就要采用构造函数的方式实例化对象
构造函数内部判断
var Singleton=function(name){
this.name=name;
}
Singleton.getInstance=function(name){
if(!this.instance){
this.instance=new Singleton(name)
}
return this.instance
}
var a=Singleton.getInstance('zmq')
var b=Singleton.getInstance('lb')
// console.log(a)
// console.log(b)
var mySingleton=(function(){
//构造器函数
function singleton(options){
options=options || {}
this.name='SingletonTestor';
this.pointX=options.pointX || 6
this.pointY=options.pointY || 10;
}
function init(){
let now=new Date() //私有方法
this.name='公共的属性'
this.getISODate()=function(){
return now.toISOString();
}
}
//缓存单例的变量
var instance;
var _static={
name:'SingletonTestor',
getInstance:function(options){
if(!instance){
instance=new singleton(options)
}
return instance
}
}
return _static
})()
var singletonTest=mySingleton.getInstance({
pointX:5,
pointY:5
})
console.log(singletonTest)
var singletonTest1=mySingleton.getInstance({
pointX:10,
pointY:10
})
es6
class Single{
constructor(name){
this.name=name
this.instance=null
}
static getInstance(name){
if(!this.instance){
this.instance=new Single(name)
}
return this.instance
}
}
console.log(Single.getInstance('zme'))
var d=Single.getInstance('LB')
console.log(d)
应用场景
描述:
- 资源共享下,避免用于资源操作时导致的性能或损耗等
- 控制资源的情况下,方便资源之间的互相通信
1.windows的Task Manager(任务管理器) 就是很典型的单例模式
2.windows的Recyle Bin (回收站) 也是典型的单例应用
3.网站的登录弹窗,无论再别的地方点击多少次,都只会弹出一个登录弹窗
4.购物车的场景
5.命名空间
登陆窗实例代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>加油,奥里给</title>
</head>
<style>
/**
* index.scss
* - Add any styles you want here!
*/
body {
background: #f5f5f5;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.top-bar {
display: flex;
justify-content: space-between;
height: 40px;
line-height: 40px;
background-color: black;
}
.top-bar_left {
padding-left: 20px;
font-size: 22px;
color: #fff;
}
.top-bar_right {
display: flex;
color: #fff;
padding-right: 40px;
}
.top-bar_right div {
cursor: pointer;
}
.top-bar_right div:hover {
color: #ccc;
}
.login-btn {
margin-right: 20px;
}
.mask-layer {
display: flex;
justify-content: center;
position: absolute;
width: 100%;
height: 100%;
padding-top: 8%;
background-color: rgba(0, 0, 0, 0.3);
}
.login-wrapper {
width: 400px;
height: 200px;
padding-left: 20px;
background-color: #fff;
border: 1px solid #ccc;
}
.login-title {
display: flex;
justify-content: space-between;
padding: 10px 10px 0 0;
}
.close-btn {
cursor: pointer;
}
.user-input {
margin-top: 20px;
}
.login-text {
display: inline-block;
width: 60px;
}
.btn-wrapper {
display: flex;
margin-top: 20px;
}
.btn-wrapper button {
padding: 0 8px;
cursor: pointer;
}
.clear-btn {
margin-left: 10px;
}
</style>
<body>
<nav class="top-bar">
<div class="top-bar_left">
LTH BLOG
</div>
<div class="top-bar_right">
<div class="login-btn">登陆</div>
<div class="signin-btn">注册</div>
</div>
</nav>
<script>
class Login {
//构造器
constructor() {
this.init();
}
//初始化方法
init() {
//新建div
let mask = document.createElement('div');
//添加样式
mask.classList.add('mask-layer');
//添加模板字符串
mask.innerHTML =
`
<div class="login-wrapper">
<div class="login-title">
<div class="title-text">登录框</div>
<div class="close-btn">×</div>
</div>
<div class="username-input user-input">
<span class="login-text">用户名:</span>
<input type="text">
</div>
<div class="pwd-input user-input">
<span class="login-text">密码:</span>
<input type="password">
</div>
<div class="btn-wrapper">
<button class="confrim-btn">确定</button>
<button class="clear-btn">清空</button>
</div>
</div>
`;
//插入元素
document.body.insertBefore(mask, document.body.childNodes[0]);
//注册关闭登录框事件
Login.addCloseLoginEvent();
}
//静态方法: 获取元素
static getLoginDom(cls) {
return document.querySelector(cls);
}
//静态方法: 注册关闭登录框事件
static addCloseLoginEvent() {
this.getLoginDom('.close-btn').addEventListener('click', () => {
//给遮罩层添加style, 用于隐藏遮罩层
this.getLoginDom('.mask-layer').style = "display: none";
})
}
//静态方法: 获取实例(单例)
static getInstance() {
if(!this.instance) {
this.instance = new Login();
} else {
//移除遮罩层style, 用于显示遮罩层
this.getLoginDom('.mask-layer').removeAttribute('style');
}
return this.instance;
}
}
// /注册点击事件
Login.getLoginDom('.login-btn').addEventListener('click', () => {
console.log('zhe')
Login.getInstance();
})
</script>
</body>
</html>
展示:
![](https://img.haomeiwen.com/i5805843/cff207db808915f3.gif)
![](https://img.haomeiwen.com/i5805843/3853d179d891df08.png)
第一次点击的时候,创建登录弹窗并且插入,当创建过之后就移除style,显示弹窗
举一反三 :
购物车 (单例模式) 静态方法版
class Cart{
constructor(){
this.list=[]
}
add(data){
this.list.push(data)
}
del(id){
this.list=this.list.filter(item=>{
if(item.id==id){
return false
}
return true
})
}
render(){
var dom=$('cartDom')
var html=''
for(let i=0;i<this.list.length;i++){
html+='<div>'+this.list[i].tit+'</div>'
}
dom.append(html)
}
static getInstance(){
if(!this.instance){
this.instance=new Cart();
}else{
console.log('已经创建过cart对象')
return
}
return this.instance
}
}
let cart=Cart.getInstance()
cart.add({id:1,tit:商品name.......})
cart.del(1)
看代码全明白,等自己写某个功能的时候,不知道怎么砍成对象,分配各个方法。那我们就多看,多学,多分析。加油
随便的一个demo 闭包版
function StorageBase(){
StorageBase.prototype.getItem=function(){
return localStorage.getItem(key)
}
StorageBase.prototype.setItem=function(){
return localStorage.setItem(key,value)
}
}
const Storage1=(function(){
let instance=null
return function (){
if(!instance){
instance=new StorageBase()
}
return instance
}
})()
const storage3=new Storage1()
console.log(storage3)
const storage2=new Storage1()
storage3.setItem('name','张三')
storage3.getItem('name') //张三
storage2.getItem('name')//张三
单例模式得应用大家最熟悉得有vuex vue-router
实例:全局数据存储对象 (vuex)
function store(){
if(store.instance){
return store.instance
}
store.instance=this
}
//同
function store(){
if(!(this instanceof store)){
return new store()
}
}
上面得代码 可以new 也可以直接使用 ,这里使用了一个静态变量instance来记录是否有进行过实例化,如果实例化了就返回这个实例,如果没有实例化说明使第一次调用,就会把this赋给这个静态变量,因为是使用new 调用,这时候得this指向得就是实例化出来得对象,并且最后会隐式得返回this
var a=new store()
var b=store()
a==b
等我具体项目中遇到类似用到单例模式的例子再来更。
网友评论