JavaScript design patterns

此文通过书籍:《learn design pattern》详细解释关于JS的设计模式。也就是那十几种模式。然后再对MVC、MVVM等深入学习。那么就是读书笔记以及扩展啦。
TODO:

第一次总结:
由于此文内容较多,算是 《learn design pattern》 这本书的简单学习吧。前面部分细读了,后面就晕了,就简单粗读了。
此文关注点:

通过Design patterns,learn DP, 深入系列 来通解DP。
我看到的东西不应是简单的语法知识,而是一种大处着眼的编程思想,解决方法,一个能够解决问题的方案。此文所讲的设计模式不即包括在JS开发涉及的设计模式,而且包括通常的软件开发。

WTF design pattern?

WIKI:https://en.wikipedia.org/wiki/Software_design_pattern(简介,历史,详细分类)

设计模式是命名、抽象和识别对可重用的面向对象设计有用的的通用设计结构。设计模式确定类和他们的实体、他们的角色和协作、还有他们的责任分配。
每一个设计模式都聚焦于一个面向对象的设计难题或问题。它描述了在其它设计的约束下它能否使用,使用它后的后果和得失。因为我们必须最终实现我们的设计模式,所以每个设计模式都提供了例子..代码来对实现进行阐释。
虽然设计模式被描述为面向对象的设计,它们基于那些已经被主流面向对象语言实现过的解决方案..

那么通俗的来讲:设计模式是一种意义上的解决方案,架构。可重用,并且切实解决问题,满足模式原型和三条规则。

Categories of design pattern

三个分类

Creational design patterns 创建型

创建型设计模式关注于对象创建的机制方法,通过该方法,对象以适应工作环境的方式被创建。基本的对象创建方法可能会给项目增加额外的复杂性,而这些模式的目的就是为了通过控制创建过程解决这个问题。

Structural design patterns 结构

结构模式关注于对象组成和通常识别的方式实现不同对象之间的关系。该模式有助于在系统的某一部分发生改变的时候,整个系统结构不需要改变。该模式同样有助于对系统中某部分没有达到某一目的的部分进行重组。

Behavioral design patterns 行为

行为模式关注改善或精简在系统中不同对象间通信。

关于类:class 说明

http://www.phpied.com/3-ways-to-define-a-javascript-class/
https://zh.wikipedia.org/wiki/%E7%B1%BB_(%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6)

这里我要理解类的概念
JavaScript是一种弱类型语言,不过类可以通过函数模拟出来。 最常见的实现这一点的方法,是先定义一个JavaScript函数,然后再使用这个新的关键字创建一个对象。可以通过这种方法像下面这样给类定义新的属性与方法。

// A car "class"
function Car( model ) {

  this.model = model;
  this.color = "silver";
  this.year  = "2012";

  this.getInfo = function () {
    return this.model + " " + this.year;
  };

}var myCar = new Car("ford");

myCar.year = "2010";

console.log( myCar.getInfo() );

模式分类详细表格

Keep in mind that there will be patterns in this table that reference the concept of ʺclassesʺ. JavaScript is a class‑less language, however classes can be simulated using functions.

创建型

enter image description here

结构型

enter image description here

行为型

enter image description here

JavaScript 设计模式 (ES5)

我们要完成的每个脚本和Web应用都可能会有它自己的独特需求,我们需要思考模式对实现来说在哪些方面能够提供真正的价值。
返回的是对象和类,那么下面我们将要注意的是:类 和 对象,并且区分。

术语:

浅谈对象

Object-oriented 语言有一个标志,就是都有类的概念,通过类可以创建任意多个具有相同属性和方法的对象。ECMAScript没有类的概念,与普通的就有区别。ES2015已经支持类了。

那么类和对象的区别

ECMA-262把对象定义:“无序属性的集合,其属性可以包含基本值、对象、函数”。散列表的概念。

MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object
CANIUSE: http://kangax.github.io/compat-table/es5/#test-Object.defineProperty
上面详细介绍了属性 和 方法

创建对象的三种基本方式:
注意这三种创建方式的差别。

var newObject = {};
// or
var newObject = Object.create( null );
var newObject = Object.create( Object.prototype );
// or
var newObject = new Object();

Object.create创建了一个拥有特定原型的对象,并且也包含选项式的特定属性.(例如,Object.create(prototype,optionalDescriptorObject))。观察下面例子中的区别。

var myCar = {
  name: "Ford Escort",
  drive: function () {
    console.log( "Weeee. I'm driving!" );
  },
  panic: function () {
    console.log( "Wait. How do you stop this thing?" );
  }
};
// Use Object.create to instantiate a new car
var yourCar = Object.create( myCar );  // 这三种创建造成的不同,即 yourCar ===myCar真假的区分。
//var yourCar = new Object( myCar );
//var yourCar = myCar;

// let us differ these.
console.log( yourCar.name );
console.log( yourCar === myCar); //false true true 
console.log( yourCar );// 这也有所不同,create() 显示是继承来的属性,而new和= 直接具有该属性。
yourCar.price =1000;
console.log(yourCar.price);
console.log(myCar.price);

设置对象属性(property)4个方法:

// ECMAScript 3 兼容形式
// 1\. “点号”法
newObject.someKey = "Hello World";
var key = newObject.someKey;
// 2\. “方括号”法
newObject["someKey"] = "Hello World";
var key = newObject["someKey"];

// 3. Object.defineProperty
// Set properties
Object.defineProperty( newObject, "someKey", {
    value: "for more control of the property's behavior",
    writable: true,
    enumerable: true,
    configurable: true
});

// 4. Object.defineProperties
// 同时设置多个属性
Object.defineProperties( newObject, {
    "someKey": {
    value: "Hello World",
    writable: true
},
    "anotherKey": {
    value: "Foo bar",
    writable: false
}
});

属性类型 与 特性:
ECMA-262定义了内部才能访问的特性(attribute),用来描述属性的各种特征。特性是内部值,放在两队方括号中,如:[[configurable]]
属性分为: 数据属性 和访问属性

  1. 数据属性
    数据属性包含一个数据值的位置,咋这个位置可以读取和写入值。有4个特性描述数据属性。
// 描述符(descriptor)
[[Configurable]]   // 默认 true   调用Object.defineProperty后 3个都为 false
[[Ennumberable]]   // 默认 true
[[Writable]]       // 默认 true
[[Value]]          // 默认 undefined

Object.defineProperty( newObject, "someKey", {
    value: "for more control of the property's behavior",
    writable: true,
    enumerable: true,
    configurable: true, // 一旦configurable为 false 那么就不能改回 true;
    });
  1. 访问器属性
var book = {
  _year : 2004,   // 注意这里的下划线 , 使用对象方法
  edition : 1,
}
Object.defineProperty(book, "year",{
  get: function() {
    return this._year;
  },
  set: function(newValue) {
    this_year = newValue;
    this.edition += newValue -2004;
  }
});
console.log(book.year);  //2004
book.year =2005;
console.log(book.edition); //2004
console.log(book.year) //2

对象方法下次再讲
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object

Constructor

构造器模式 / 构造函数模式

对象构造器是被用来创建特殊类型的对象的,首先它要准备使用的对象,其次在对象初次被创建时,通过接收参数,构造器要用来对成员的属性和方法进行赋值。

基础构造器 :this
原型构造器 :this + prototype

Module

模块是任何健壮的应用程序体系结构不可或缺的一部分,特点是有助于保持应用项目的代码单元既能清晰地分离又有组织。
模块化模式用来进一步模拟类的概念,通过这样一种方式:我们可以在一个单一的对象中包含公共/私有的方法和变量,从而从全局范围中屏蔽特定的部分。
模块模式使用闭包的方式来将”私有信息”,状态和组织结构封装起来。提供了一种将公有和私有方法,变量封装混合在一起的方式,这种方式防止内部信息泄露到全局中,从而避免了和其它开发者接口发生冲图的可能性。在这种模式下只有公有的API 会返回,其它将全部保留在闭包的私有空间中。

在JavaScript中,实现模块有几个选项,他们包括:

http://rmurphey.com/blog/2009/10/15/using-objects-to-organize-your-code

简单的讲:利用闭包实现公有和私有的区分, 理解封装的概念

这里有个JQuery的导入混合模式,是需要注意的。 注意其他库的对模块模式的使用。

reveal module

缺点

这个模式的一个缺点是如果私有函数需要使用公有函数,那么这个公有函数在需要打补丁的时候就不能被重载。因为私有函数仍然使用的是私有的实现,并且这个模式不能用于公有成员,只用于函数。

var myRevealingModule = function () {

        var privateCounter = 0;

        function privateFunction() {
            privateCounter++;
        }

        function publicFunction() {
            publicIncrement();
        }

        function publicIncrement() {
            privateFunction();
        }

        function publicGetCount(){
          return privateCounter;
        }

        // Reveal public pointers to
        // private functions and properties       

       return {
            start: publicFunction,
            increment: publicIncrement,
            count: publicGetCount
        };

    }();

myRevealingModule.start();

singleton

单例模式

var SingletonTester = (function () {

  // options: an object containing configuration options for the singleton
  // e.g var options = { name: "test", pointX: 5};
  function Singleton( options )  {

    // set options to the options supplied
    // or an empty object if none are provided
    options = options || {};

    // set some properties for our singleton
    this.name = "SingletonTester";
    this.pointX = options.pointX || 6;
    this.pointY = options.pointY || 10; 
  }

  // our instance holder
  var instance;

  // an emulation of static variables and methods
  var _static  = {  

    name:  "SingletonTester",

    // Method for getting an instance. It returns
    // a singleton instance of a singleton object
    getInstance:  function( options ) {
      console.log(instance);   
      if( instance  ===  undefined )  {    // 这里也就是单例模式重要判断,检测instance
        instance = new Singleton( options );   
      }   
      return  instance; 
    } 
  }; 
  return  _static;
})();
// 第一个实例
var singletonTest  =  SingletonTester.getInstance({
  pointX:  5
});
console.log( singletonTest.pointX );
console.log( singletonTest.instance); // 立即调用函数表达式,内部变量外部是无法访问的。
// 第二个实例
var singletonTest1  =  SingletonTester.getInstance({
  pointX:  6
});
console.log( singletonTest1.pointX );
console.log( singletonTest === singletonTest1);

// console运行结果
 undefined
 5
 undefined
 Singleton {name: "SingletonTester", pointX: 5, pointY: 10}
 5
 true

简单来看,对于两个创建的实例是完全相等的,对其的更改会同步出现在两个实例上。

这是一篇介绍 单例模式的文章: 涉及其中的各种问题。单例模式的文章:
http://www.ibm.com/developerworks/webservices/library/co-single/index.html

Observer & Publish/Sbuscribe pattern

观察者模式

在javascript时间里面,通常我们使用一种叫做发布/订阅模式的变体来实现观察者模式.
即: Publish/Sbuscribe pattern

Mediator

中介者模式

Prototype

原型模式

The GoF refer to the prototype pattern as one which creates objects based on a template of an existing object through cloning.

关于原型的问题:learn design pattern 和 红宝书 不一样..总体感觉概念有出入,还得继续查资料细看这里。

前者:继承 ,基于一个现有对象的模板创建对象
第一种方式:

var myCar = {
  name: "Ford Escort",
  drive: function () {
    console.log( "Weeee. I'm driving!" );
  },
  panic: function () {
    console.log( "Wait. How do you stop this thing?" );
  }
};

// Use Object.create to instantiate a new car
//var yourCar = Object.create( myCar );
//var yourCar =  myCar;
var yourCar = new Object( myCar ); // 这里的创建方式不同,结果也不同。

console.log( yourCar.name );
console.log( yourCar );
console.log( myCar);
console.log( yourCar === myCar); //由创建方式来看结果
yourCar.price =1000;
console.log(yourCar.price);
console.log(myCar.price);

第二种实现方式:

var beget = (function () {
    function F() {}
    return function ( proto ) {
        F.prototype = proto;
        return new F();
    };
})();
var xx = { 
 get:"right",
 out:" false"
};
var yy = beget(xx);
var zz = beget(xx);
console.log( yy===zz);  // false 这里是false
console.log(yy);
console.log(yy.get)

后者(红宝书)

// 第一种:
function Person() {};
Person.prototype = {
  constructor:Person,
  name:"test",
  age :10
};
var p1 = new Person();
var p2 = new Person();
console.log( p1===p2);  // false 
// 第二种:
function Person() {};
Person.prototype = {
  constructor:Person,
  name:"test",
  age :10
};
var p1 = new Person();
var p2 = new Person();
p1.name = 30;
console.log(p1.name ===p2.name); // false
console.log( p2.name ); // test  
console.log( p1===p2); // false
// 第三种:对于引用类型的值
function Person() {};
Person.prototype = {
  constructor:Person,
  name:"test",
  age :10,
  array:[1,2,3,4]
};
var p1 = new Person();
var p2 = new Person();
p1.array.push(30);
console.log(p1.array ===p2.array); // true 这里是true了,
console.log( p2.array ) // [1,2,3,4,30]
console.log( p1===p2); //false

对于上面的情况来说:就第二种和第三种, 要区分 基本值、函数 与 其他引用类型如数组,通过console可以看出不同。

基本类型 引用类型的区分,简单讲要看下数据类型

Command

命令模式

模式旨在将函数的调用、请求和操作封装成一个单一的对象,然后对这个对象进行一系列的处理。

Facade

外观模式:又称门面模式

隐藏内在的复杂性,提高一个舒适的对外接口

Factory

工厂模式

Mixin

混合模式

Decorator

装饰模式

Flyweight

享元模式

享元模式是一个优化重复、缓慢和低效数据共享代码的经典结构化解决方案。它的目标是以相关对象尽可能多的共享数据,来减少应用程序中内存的使用(例如:应用程序的配置、状态等)。

JavaScript MV* 架构模式

架构模式

好吧,通过简单的阅读,发现并不能学的什么。还是必须得实际写代码,必须写一遍。
决定使用VUE.JS BACKBONE都写点东西。

模块化的JavaScript

模板规范:先想一想,为什么模块很重要?
因为有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块。
但是,这样做有一个前提,那就是大家必须以同样的方式编写模块,否则你有你的写法,我有我的写法,岂不是乱了套!

https://www.zhihu.com/question/20351507

Scripts Loaders

脚本加载器

RequireJS 、 curl.js。

RequireJS is a JavaScript file and module loader. It is optimized for in-browser use, but it can be used in other JavaScript environments, like Rhino and Node. Using a modular script loader like RequireJS will improve the speed and quality of your code.

这里我也必须学习我最长看到的Require.js

AMD :Asynchronous Module Definition

A Format For Writing Modular JavaScript In The Browser

CMD

CommonJS


JQuery 中的设计模式

从JQuery的源码分析,源码中所用的设计模式

JQuery 插件的设计模式

涉及简单的JQuery插件开发

命名空间模式

几乎所有重要的 Javascript 程序中都会用到命名空间。除非我们只是编写简单的代码,否则尽力确保正确地实现命名空间是很有必要的。这也能避免自己的代码收到第三方代码的污染。本小节将阐述以下设计模式: