介绍

本篇主要是介绍创建对象方面的模式的下篇,利用各种技巧可以极大地避免了错误或者可以编写出非常精简的代码。

模式6:函数语法糖

函数语法糖是为一个对象快速添加方法(函数)的扩展,这个主要是利用prototype的特性,代码比较简单,我们先来看一下实现代码:

if (typeof Function.prototype.method !== "function") {
Function.prototype.method = function (name, implementation) {
this.prototype[name] = implementation;
return this;
};
} 扩展对象的时候,可以这么用: var Person = function (name) {
this.name = name;
}
.method('getName',
function () {
return this.name;
})
.method('setName', function (name) {
this.name = name;
return this;
}); 这样就给Person函数添加了getName和setName这2个方法,接下来我们来验证一下结果: var a = new Person('Adam');
console.log(a.getName()); // 'Adam'
console.log(a.setName('Eve').getName()); // 'Eve' 模式7:对象常量 对象常量是在一个对象提供set,get,ifDefined各种方法的体现,而且对于set的方法只会保留最先设置的对象,后期再设置都是无效的,已达到别人无法重载的目的。实现代码如下: var constant = (function () {
var constants = {},
ownProp = Object.prototype.hasOwnProperty,
// 只允许设置这三种类型的值
allowed = {
string: 1,
number: 1,
boolean: 1
},
prefix = (Math.random() + "_").slice(2); return {
// 设置名称为name的属性
set: function (name, value) {
if (this.isDefined(name)) {
return false;
}
if (!ownProp.call(allowed, typeof value)) {
return false;
}
constants[prefix + name] = value;
return true;
},
// 判断是否存在名称为name的属性
isDefined: function (name) {
return ownProp.call(constants, prefix + name);
},
// 获取名称为name的属性
get: function (name) {
if (this.isDefined(name)) {
return constants[prefix + name];
}
return null;
}
};
} ()); 验证代码如下: // 检查是否存在
console.log(constant.isDefined("maxwidth")); // false // 定义
console.log(constant.set("maxwidth", 480)); // true // 重新检测
console.log(constant.isDefined("maxwidth")); // true // 尝试重新定义
console.log(constant.set("maxwidth", 320)); // false // 判断原先的定义是否还存在
console.log(constant.get("maxwidth")); // 模式8:沙盒模式 沙盒(Sandbox)模式即时为一个或多个模块提供单独的上下文环境,而不会影响其他模块的上下文环境,比如有个Sandbox里有3个方法event,dom,ajax,在调用其中2个组成一个环境的话,和调用三个组成的环境完全没有干扰。Sandbox实现代码如下: function Sandbox() {
// 将参数转为数组
var args = Array.prototype.slice.call(arguments),
// 最后一个参数为callback
callback = args.pop(),
// 除最后一个参数外,其它均为要选择的模块
modules = (args[0] && typeof args[0] === "string") ? args : args[0],
i; // 强制使用new操作符
if (!(this instanceof Sandbox)) {
return new Sandbox(modules, callback);
} // 添加属性
this.a = 1;
this.b = 2; // 向this对象上需想添加模块
// 如果没有模块或传入的参数为 "*" ,则以为着传入所有模块
if (!modules || modules == '*') {
modules = [];
for (i in Sandbox.modules) {
if (Sandbox.modules.hasOwnProperty(i)) {
modules.push(i);
}
}
} // 初始化需要的模块
for (i = 0; i < modules.length; i += 1) {
Sandbox.modules[modules[i]](this);
} // 调用 callback
callback(this);
} // 默认添加原型对象
Sandbox.prototype = {
name: "My Application",
version: "1.0",
getName: function () {
return this.name;
}
}; 然后我们再定义默认的初始模块: Sandbox.modules = {}; Sandbox.modules.dom = function (box) {
box.getElement = function () {
};
box.getStyle = function () {
};
box.foo = "bar";
}; Sandbox.modules.event = function (box) {
// access to the Sandbox prototype if needed:
// box.constructor.prototype.m = "mmm";
box.attachEvent = function () {
};
box.detachEvent = function () {
};
}; Sandbox.modules.ajax = function (box) {
box.makeRequest = function () {
};
box.getResponse = function () {
};
}; 调用方式如下: // 调用方式
Sandbox(['ajax', 'event'], function (box) {
console.log(typeof (box.foo));
// 没有选择dom,所以box.foo不存在
}); Sandbox('ajax', 'dom', function (box) {
console.log(typeof (box.attachEvent));
// 没有选择event,所以event里定义的attachEvent也不存在
}); Sandbox('*', function (box) {
console.log(box); // 上面定义的所有方法都可访问
}); 通过三个不同的调用方式,我们可以看到,三种方式的上下文环境都是不同的,第一种里没有foo; 而第二种则没有attachEvent,因为只加载了ajax和dom,而没有加载event; 第三种则加载了全部。 模式9:静态成员 静态成员(Static Members)只是一个函数或对象提供的静态属性,可分为私有的和公有的,就像C#或Java里的public static和private static一样。 我们先来看一下公有成员,公有成员非常简单,我们平时声明的方法,函数都是公有的,比如: // 构造函数
var Gadget = function () {
}; // 公有静态方法
Gadget.isShiny = function () {
return "you bet";
}; // 原型上添加的正常方法
Gadget.prototype.setPrice = function (price) {
this.price = price;
}; // 调用静态方法
console.log(Gadget.isShiny()); // "you bet" // 创建实例,然后调用方法
var iphone = new Gadget();
iphone.setPrice(500); console.log(typeof Gadget.setPrice); // "undefined"
console.log(typeof iphone.isShiny); // "undefined"
Gadget.prototype.isShiny = Gadget.isShiny;
console.log(iphone.isShiny()); // "you bet" 而私有静态成员,我们可以利用其闭包特性去实现,以下是两种实现方式。 第一种实现方式: var Gadget = (function () {
// 静态变量/属性
var counter = 0; // 闭包返回构造函数的新实现
return function () {
console.log(counter += 1);
};
} ()); // 立即执行 var g1 = new Gadget(); // logs 1
var g2 = new Gadget(); // logs 2
var g3 = new Gadget(); // logs 3 可以看出,虽然每次都是new的对象,但数字依然是递增的,达到了静态成员的目的。 第二种方式: var Gadget = (function () {
// 静态变量/属性
var counter = 0,
NewGadget; //新构造函数实现
NewGadget = function () {
counter += 1;
}; // 授权可以访问的方法
NewGadget.prototype.getLastId = function () {
return counter;
}; // 覆盖构造函数
return NewGadget;
} ()); // 立即执行 var iphone = new Gadget();
iphone.getLastId(); //
var ipod = new Gadget();
ipod.getLastId(); //
var ipad = new Gadget();
ipad.getLastId(); // 数字也是递增了,这是利用其内部授权方法的闭包特性实现的。 总结 这是对象创建模式的下篇,两篇一起总共9种模式,是我们在日常JavaScript编程中经常使用的对象创建模式,不同的场景起到了不同的作用,希望大家根据各自的需求选择适用的模式。 参考:http://shichuan.github.com/javascript-patterns/#object-creation-patterns 同步与推荐 本文已同步至目录索引:深入理解JavaScript系列 深入理解JavaScript系列文章,包括了原创,翻译,转载等各类型的文章,如果对你有用,请推荐支持一把,给大叔写作的动力。

深入理解JavaScript系列(48):对象创建模式(下篇)的更多相关文章

  1. 深入理解JavaScript系列(47):对象创建模式(上篇)

    介绍 本篇主要是介绍创建对象方面的模式,利用各种技巧可以极大地避免了错误或者可以编写出非常精简的代码. 模式1:命名空间(namespace) 命名空间可以减少全局命名所需的数量,避免命名冲突或过度. ...

  2. 深入理解JavaScript系列(36):设计模式之中介者模式

    介绍 中介者模式(Mediator),用一个中介对象来封装一系列的对象交互.中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互. 主要内容来自:http://www ...

  3. 深入理解JavaScript系列(49):Function模式(上篇)

    介绍 本篇主要是介绍Function方面使用的一些技巧(上篇),利用Function特性可以编写出很多非常有意思的代码,本篇主要包括:回调模式.配置对象.返回函数.分布程序.柯里化(Currying) ...

  4. 深入理解JavaScript系列(46):代码复用模式(推荐篇)

    介绍 本文介绍的四种代码复用模式都是最佳实践,推荐大家在编程的过程中使用. 模式1:原型继承 原型继承是让父对象作为子对象的原型,从而达到继承的目的: function object(o) { fun ...

  5. 深入理解JavaScript系列(45):代码复用模式(避免篇)

    介绍 任何编程都提出代码复用,否则话每次开发一个新程序或者写一个新功能都要全新编写的话,那就歇菜了,但是代码复用也是有好要坏,接下来的两篇文章我们将针对代码复用来进行讨论,第一篇文避免篇,指的是要尽量 ...

  6. 深入理解JavaScript系列(42):设计模式之原型模式

    介绍 原型模式(prototype)是指用原型实例指向创建对象的种类,并且通过拷贝这些原型创建新的对象. 正文 对于原型模式,我们可以利用JavaScript特有的原型继承特性去创建对象的方式,也就是 ...

  7. 深入理解JavaScript系列(40):设计模式之组合模式

    介绍 组合模式(Composite)将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性. 常见的场景有asp.net里的控件机制(即control ...

  8. 深入理解JavaScript系列(37):设计模式之享元模式

    介绍 享元模式(Flyweight),运行共享技术有效地支持大量细粒度的对象,避免大量拥有相同内容的小类的开销(如耗费内存),使大家共享一个类(元类). 享元模式可以避免大量非常相似类的开销,在程序设 ...

  9. 深入理解JavaScript系列(30):设计模式之外观模式

    介绍 外观模式(Facade)为子系统中的一组接口提供了一个一致的界面,此模块定义了一个高层接口,这个接口值得这一子系统更加容易使用. 正文 外观模式不仅简化类中的接口,而且对接口与调用者也进行了解耦 ...

随机推荐

  1. C#文件和目录的操作

    根据文件名获取文件 /// <summary> /// 根据文件名获取文件 /// </summary> /// <param name="directory& ...

  2. SystemID

    A:BJQUANYONG-B:CCC332322987612323008002DDD A:JHDUJIA-B:CCC1365323754641263423809708001DDD A:GUANGZHO ...

  3. 转载-----Java Longest Palindromic Substring(最长回文字符串)

    转载地址:https://www.cnblogs.com/clnchanpin/p/6880322.html 假设一个字符串从左向右写和从右向左写是一样的,这种字符串就叫做palindromic st ...

  4. TCP/IP学习笔记(2)-数据链路层

    数据链路层有三个目的: 为IP模块发送和接收IP数据报. 为ARP模块发送ARP请求和接收ARP应答. 为RARP发送RARP请求和接收RARP应答 ip大家都听说过.至于ARP和RARP,ARP叫做 ...

  5. [ActionSprit 3.0] FMS客户端与服务器端交互(传参)

    客户端as: import flash.net.NetConnection; import flash.events.NetStatusEvent; var nc:NetConnection = ne ...

  6. Archlinux下virtualbox报错'/sbin/rcvboxdrv setup'

    因为刚刚换成archlinux系统,安装virtualbox的时候报错了.如下图: 可是怎么解决呢?我看了很多资料大多数是ubuntu的,没有archlinux的. 但是原理都差不多我借着也就研究出来 ...

  7. Struts2框架action层学习心得体会

    在struts2框架中,当action处理完之后,就应该向用户返回结果信息,该任务被分为两部分:结果类型和结果本身. 结果类型提供了返回给用户信息类型的实现细节.结果类型通常在Struts2中就已预定 ...

  8. selenium上传图片

    在我们使用selenium的时候碰到上传图片.文件时一般都可以先定位然后直接send_keys,但是有的却不行,selenium也没有提供其它的办法,只能靠第三方软件来解决 我们要借助一个叫AutoI ...

  9. SQL语句之数据库操作

    SQL语句系列 1.SQL语句之行操作 2.SQL语句之表操作 3.SQL语句之数据库操作 4.SQL语句之用户管理 占坑,带写……

  10. 【Python】批量检测百度权重

    挖洞过程中收集了站点后,我一般习惯查看站点的百度权重值,为了方便,写了一个简单的脚本, 至于结果如何显示,看个人需求吧,我这里只是简单的列一下,脚本如下: #coding:utf-8 import r ...