深入理解JavaScript系列(48):对象创建模式(下篇)


Posted in Javascript onMarch 04, 2015

介绍

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

模式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")); // 480

模式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(); // 1

var ipod = new Gadget();

ipod.getLastId(); // 2

var ipad = new Gadget();

ipad.getLastId(); // 3

数字也是递增了,这是利用其内部授权方法的闭包特性实现的。

总结

这是对象创建模式的下篇,两篇一起总共9种模式,是我们在日常JavaScript编程中经常使用的对象创建模式,不同的场景起到了不同的作用,希望大家根据各自的需求选择适用的模式。

Javascript 相关文章推荐
iframe 异步加载技术及性能分析
Jul 19 Javascript
最常用的12种设计模式小结
Aug 09 Javascript
解决jquery submit()提交表单提示:f[s] is not a function
Jan 23 Javascript
JavaScript禁止页面操作的示例代码
Dec 17 Javascript
JS删除字符串中重复字符方法
Mar 09 Javascript
使用ajaxfileupload.js实现ajax上传文件php版
Jun 26 Javascript
AngularJS 过滤器的简单实例
Jul 27 Javascript
关于JavaScript和jQuery的类型判断详解
Oct 08 Javascript
理解javascript中的闭包
Jan 11 Javascript
Angular.Js中ng-include指令的使用与实现
May 07 Javascript
node.js将MongoDB数据同步到MySQL的步骤
Dec 10 Javascript
使用Node.js写一个代码生成器的方法步骤
May 10 Javascript
js计算德州扑克牌面值的方法
Mar 04 #Javascript
深入理解JavaScript系列(47):对象创建模式(上篇)
Mar 04 #Javascript
深入理解JavaScript系列(46):代码复用模式(推荐篇)详解
Mar 04 #Javascript
深入理解JavaScript系列(45):代码复用模式(避免篇)详解
Mar 04 #Javascript
深入理解JavaScript系列(44):设计模式之桥接模式详解
Mar 04 #Javascript
JS实现FLASH幻灯片图片切换效果的方法
Mar 04 #Javascript
javascript下拉框选项单击事件的例子分享
Mar 04 #Javascript
You might like
php连接函数implode与分割explode的深入解析
2013/06/26 PHP
php无限极分类递归排序实现方法
2014/11/11 PHP
PHP批量获取网页中所有固定种子链接的方法
2016/11/18 PHP
实例介绍PHP中zip_open()函数用法
2019/02/15 PHP
TP5框架使用QueryList采集框架爬小说操作示例
2020/03/26 PHP
收藏Javascript中常用的55个经典技巧
2007/08/12 Javascript
JavaScript中几种常见排序算法小结
2011/02/22 Javascript
Javascript 闭包引起的IE内存泄露分析
2012/05/23 Javascript
JavaScript中圆括号()和方括号[]的特殊用法疑问解答
2013/08/06 Javascript
js获取客户端网卡的IP地址、MAC地址
2014/03/26 Javascript
深入了解JavaScript中的Symbol的使用方法
2015/07/28 Javascript
JS实时弹出新消息提示框并有提示音响起的实现代码
2016/04/20 Javascript
jQuery插件formValidator实现表单验证
2016/05/23 Javascript
通过js修改input、select默认字体颜色
2017/04/19 Javascript
ajax+node+request爬取网络图片的实例(宅男福利)
2017/08/28 Javascript
Vue Element UI + OSS实现上传文件功能
2019/07/31 Javascript
解决vue中axios设置超时(超过5分钟)没反应的问题
2020/09/04 Javascript
[11:01]2014DOTA2西雅图邀请赛 冷冷带你探秘威斯汀
2014/07/08 DOTA
[02:37]TI8勇士令状不朽珍藏II视频展示
2018/06/23 DOTA
[08:38]DOTA2-DPC中国联赛 正赛 VG vs Elephant 选手采访
2021/03/11 DOTA
python 换位密码算法的实例详解
2017/07/19 Python
Django中ORM外键和表的关系详解
2019/05/20 Python
对python 中class与变量的使用方法详解
2019/06/26 Python
Keras Convolution1D与Convolution2D区别说明
2020/05/22 Python
在python3.64中安装pyinstaller库的方法步骤
2020/06/02 Python
python更新数据库中某个字段的数据(方法详解)
2020/11/18 Python
Parts Express:音频、视频和扬声器的第一来源
2017/04/25 全球购物
巴西男士胡须和头发护理产品商店:Beard
2017/11/13 全球购物
四年大学生活的自我评价范文
2014/02/07 职场文书
十一酒店活动方案
2014/02/20 职场文书
公司贷款承诺书
2014/05/30 职场文书
新闻发布会活动策划方案
2014/09/15 职场文书
法人代表证明书
2014/09/18 职场文书
优秀班集体申报材料
2014/12/25 职场文书
硕士学位论文评语
2014/12/31 职场文书
法制教育观后感
2015/06/17 职场文书