《JavaScript设计模式与开发》笔记 7.单例模式

废话一箩筐就这个原来

var instance;
return function asdf(name){
   if(!this.instance){
        this.instance = new asdf(name);
   }
};
  •  1.实现单例模式
    • 1.第一种单例模式
    • 2.第二种单例模式
  •  2.透明单例模式
  •  3.用代理模式实现单例模式
  •  4.JavaScript中的代理模式
  •  5.惰性单例
  •  6.通用的惰性单例

1.实现单例模式

1.第一种单例模式

var Singleton = function(name){
    this.name = name;
    this.instance = null;
}
Singleton.prototype.getName = function(){
    console.log(this.name);
}
Singleton.getInstance = function(name){
    if(!this.instance){
        this.instance = new Singleton(name);
    }
    return this.instance;
}
var a = Singleton.getInstance('slash');
var b = Singleton.getInstance('Axxxxl');
console.log(a===b);

2.简单变形

var Singleton = function(name){
    this.name = name;
}
Singleton.prototype.getName = function(){
    console.log(this.name);
}
Singleton.getInstance = (function(){
    var instance = null;
    return function(name){
        if(!instance){
            instance = new Singleton(name);
        }
    }
})()
var a = Singleton.getInstance('slash');
var b = Singleton.getInstance('roXXXse');
console.log(a===b);

2.透明单例模式

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

</body>
<script>
    var createDiv = (function(){
        var instance;
        var createDiv = function(html){
            if(instance){
                return instance;
            }
            this.html = html;
            this.init();
            return instance = this;
        }
        createDiv.prototype.init = function(){
            var div = document.createElement('div');
            div.innerHTML = this.html;
            document.body.appendChild(div);
        }
        return createDiv;
    })();
    var a = new createDiv("Slash");
    var b = new createDiv("Axxxxxl");
    console.log(a===b);
    alert(a===b);
</script>
</html>

观察现在的Singleton构造函数

var createDiv = function(html){
            if(instance){
                return instance;
            }
            this.html = html;
            this.init();
            return instance = this;
        }

在这段代码中,CreateDiv的构造函数实际上负责了两件事情。第一个是创建对象和执行初始化init方法;第二个保证只有一个对象,虽然我们目前还没有接触过“单一职责元原则”的概念 但可以明确的是,这是一种不好的做法,但至少看起来很奇怪。

假如我们某天需要利用这个类,在页面中创建千千万的div,既要让这个类从单例类编程一个普通的可产生多个实例的类,那么我们必须改写CreateDiv这个类

3.用代理实现单例模式

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

</body>
<script>
    var CreateDiv = function(html){
        this.html = html;
        this.init();
    }
    CreateDiv.prototype.init = function(){
        var div = document.createElement('div');
        div.innerHTML = this.html;
        document.body.appendChild(div);
    };
    var ProxySingletonCreateDiv = (function(){
        var instance;
        return function(html){
            if(!instance){
                instance = new CreateDiv(html);
            }
            return instance;
        }
    })();
    var b = new ProxySingletonCreateDiv("Axxxl");
    var a = new ProxySingletonCreateDiv('Slash');
    alert(a===b);
</script>
</html>

4.javascript中的单例模式

1.命名空间

上面的几种单例模式会造成全局变量,但可以适当地使用命名空间,并不会杜绝全局变量,但可以减少全局变量。 最简单的命名空间

var namespace1 = {
    a:function(){
        console.log(1);
    },
    b:function(){
        console.log(2);
    }
}

把a和b都定义为namespace的属性,这样可以减少变量和全局作用域打交道的机会,但是我们还可以动态地创建命名空间,代码如下:

var myApp = {};
    myApp.namespace = function(name){
        var parts = name.split('.');
        var current = myApp;
        for(var i in parts){
            if(!current[parts[i]]){
                current[parts[i]] ={};
            }
            current = current[parts[i]];
        }
    }
    myApp.namespace('event');
    myApp.namespace('dom.style');
    console.log(myApp);

//上述代码相当于

var myApp ={
    event:{},
    dom:{
        style:{}
    }
}

2.使用闭包封装私有变量

这种方法把一些变量封装在闭包的内部,值暴漏一些借口跟外界通信

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

我们用下划线来约定私有变量_name 和_age 他们被封装在闭包生产的作用域中,外部是访问不到这两个变量的(废话!),这就避免了全局的命令污染

5.惰性单例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<button id="loginBtn">登录</button>
</body>
<script>
var loginlayer = (function(){
    var div = document.createElement(div);
    div.innerHTML="我是登录悬浮窗";
    div.style.display='none';
    document.body.appendChild(div);
    return div;
})();   //开始执行
document.getElementById("loginBtn").onclick = function(){
    loginlayer.style='block';
}
</script>
</html>

这种方式有一个种问题,也许我们根本不需要登录悬浮窗,因为登录悬浮窗总是一开始就创建好了,那么很有可能将浪费一些DOM节点。 现在改写代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<button id="loginBtn">登录</button>
</body>
<script>
var loginlayer = function(){
    var div = document.createElement(div);
    div.innerHTML="我是登录悬浮窗";
    div.style.display='none';
    document.body.appendChild(div);
    return div;
};
document.getElementById("loginBtn").onclick = function(){
    loginlayer = createloginlayer();  //创建节点
    loginlayer.style='block';
}
</script>
</html>

虽然简单的改写了一下闭包,但是去了单例的特性,当我们每次点击登录按钮的时候,都会创建一个新的登录悬浮窗DIV,虽然我们可以再点击悬浮窗上的关闭按钮式把这个悬浮窗从页面中删除掉,但这样频繁地创建和删除节点是不合理的 简单判断是否有DIV

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<button id="loginBtn">登录</button>
</body>
<script>
var createloginlayer = function(){
    var div;
    return function(){
        if(!div){
            div = document.createElement(div);
            div.innerHTML="我是登录悬浮窗";
            div.style.display='none';
            document.body.appendChild(div);
        }
        return div;
    }
}();
document.getElementById("loginBtn").onclick = function(){
    loginlayer = createloginlayer();  //创建节点
    loginlayer.style='block';
}
</script>
</html>

6.通用的惰性单例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<button id="loginBtn">登录</button>
<button id="div1">叫我退出页面好了</button>
</body>
<script>
    var getSingle = function(fn){
        var result;
        return function(){
            return 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 createLoginiframe = function(){
        var iframe = document.createElement('iframe');
        document.body.appendChild(iframe);
        return iframe;
    }
   // var createSingleLoginlayer = getSingle(createLoginLayer);
    var createSingleLoginlayer = getSingle(createLoginiframe);
    document.getElementById("loginBtn").onclick = function(){
        loginlayer = createSingleLoginlayer();  //创建节点
        loginlayer.src="http://www.baidu.com";
    }


</script>
</html>
原文地址:https://www.cnblogs.com/subtract/p/7932025.html