blog

javascript设计模式学习笔记 | Nodejs最佳实践 | javascript标准对象

View project on GitHub
单例模式的定义是: 保证一个类仅有一个实例,并提供一个访问它的全局访问点。

任何只需要做一次的事情,都可以用单例实现。

单例模式是一种常用的模式,有一些对象我们往往只需要一个,比如线程池、全局缓存、浏 览器中的 window 对象等。在 JavaScript 开发中,单例模式的用途同样非常广泛。试想一下,当我 们单击登录按钮的时候,页面中会出现一个登录浮窗,而这个登录浮窗是唯一的,无论单击多少 次登录按钮,这个浮窗都只会被创建一次,那么这个登录浮窗就适合用单例模式来创建。

单例模式的核心是确保只有一个实例,并提供全局访问。

作为普通的开发者,我们有必要尽量减少全局变量的使用,即使需要,也要把它的污染降到 最低。以下几种方式可以相对降低全局变量带来的命名污染。

动态地创建命名空间
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.dir(MyApp);
// 上述代码等价于:
var MyApp = {
  event: {},
  dom: {
    style: {}
  }
};

使用闭包封装私有变量

var user = ( function () {
  var __name = 'sven', __age = 29;
  return {
    getUserInfo: function () {
      return __name + '-' + __age;
    }
  }
} )();
JavaScript 中的单例模式(惰性单例技术)

惰性单例指的是在需要的时候才创建对象实例。惰性单例是单例模式的重点,这种技术在实 际开发中非常有用

创建单例对象( 创建唯一实例对象)

//抽象管理单例的逻辑 单一职责【单例核心】
var getSingle = function( fn ){
  var result;
  return function(){
    return result || ( result = fn .apply(this, arguments ) );
  } 
};

// 接下来将用于创建登录浮窗的方法用参数 fn 的形式传入 getSingle,我们不仅可以传入 createLoginLayer,还能传入 createScript、createIframe、createXhr 等。

// 创建登录浮窗 
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';
};


// 下面我们再试试创建唯一的 iframe 用于动态加载第三方页面:
var createSingleIframe = getSingle(function() {
  var iframe = document.createElement("iframe");
  document.body.appendChild(iframe);
  return iframe;
});
document.getElementById("loginBtn").onclick = function() {
  var loginLayer = createSingleIframe();
  loginLayer.src = "http://baidu.com";
};


// 这种单例模式的用途远不止创建对象,比如我们通常渲染完页面中的一个列表之后,接下来要给这个列表绑定 click 事件,如果是通过 ajax 动态往列表里追加数据,在使用事件代理的前提下,click 事件实际上只需要在第一次渲染列表的时候被绑定一次,但是我们不想去判断当前是否是第一次渲染列表,利用getSingle函数只绑定一个事件代码实现:
var bindEvent = getSingle(function() {
  document.getElementById("div1").onclick = function() {
    alert("click");
  };
  return true;
});
var render = function() {
  console.log("开始渲染列表");
  bindEvent();
};
render();
render();
render();

render 函数和 bindEvent 函数都分别执行了 3 次,但 div 实际上只被绑定了一个事件。

总结

在 getSinge 函数中,实际上也提到了闭包和高阶函数的概念。单例模式是一种简单但非常实 用的模式,特别是惰性单例技术,在合适的时候才创建对象,并且只创建唯一的一个。更奇妙的 是,创建对象和管理单例的职责被分布在两个不同的方法中,这两个方法组合起来才具有单例模 式的威力。