深入理解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 相关文章推荐
js function定义函数使用心得
Apr 15 Javascript
Javascript 类型转换方法
Oct 24 Javascript
Javascript 检测键盘按键信息及键码值对应介绍
Jan 03 Javascript
原生JS操作网页给p元素添加onclick事件及表格隔行变色
Dec 01 Javascript
详解js闭包
Sep 02 Javascript
jquery实现鼠标经过显示下划线的渐变下拉菜单效果代码
Aug 24 Javascript
浅谈Javascript中Object与Function对象
Sep 26 Javascript
gulp-htmlmin压缩html的gulp插件实例代码
Jun 06 Javascript
Js遍历键值对形式对象或Map形式的方法
Aug 08 Javascript
整理关于Bootstrap警示框的慕课笔记
Mar 29 Javascript
django js 实现表格动态标序号的实例代码
Jul 12 Javascript
flexible.js实现移动端rem适配方案
Apr 07 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
javascript 函数式编程
2007/08/16 Javascript
js键盘上下左右键怎么触发function(实例讲解)
2013/12/14 Javascript
js文本框输入内容智能提示效果
2015/12/02 Javascript
jQuery增加、删除及修改select option的方法
2016/08/19 Javascript
微信小程序 window_x64环境搭建
2016/09/30 Javascript
详解Jquery 遍历数组之$().each方法与$.each()方法介绍
2017/01/09 Javascript
深入浅出es6模板字符串
2017/08/26 Javascript
jQuery实现IE输入框完成placeholder标签功能的方法
2017/09/20 jQuery
动态加载、移除js/css文件的示例代码
2018/03/20 Javascript
灵活使用console让js调试更简单的方法步骤
2019/04/23 Javascript
解决微信小程序中的滚动穿透问题
2019/09/16 Javascript
Vuex实现数据共享的方法
2019/12/20 Javascript
[03:55]2014DOTA2国际邀请赛 Fnatic经理采访赢DK在情理之中
2014/07/10 DOTA
Python中的列表生成式与生成器学习教程
2016/03/13 Python
python 随机数使用方法,推导以及字符串,双色球小程序实例
2017/09/12 Python
Python中进程和线程的区别详解
2017/10/29 Python
Python自动发送邮件的方法实例总结
2018/12/08 Python
Dlib+OpenCV深度学习人脸识别的方法示例
2019/05/14 Python
Python中模块(Module)和包(Package)的区别详解
2019/08/07 Python
Python将QQ聊天记录生成词云的示例代码
2021/02/10 Python
W3C公布最新的HTML5标准草案
2008/10/17 HTML / CSS
美国杰西潘尼官网:JCPenney
2019/06/12 全球购物
德国2018年度最佳在线药房:Bodfeld Apotheke
2019/11/04 全球购物
美国折扣地毯销售网站:Rugs.com
2020/03/27 全球购物
函数指针的定义是什么
2016/08/14 面试题
Python的两道面试题
2013/06/29 面试题
销售员自我评价怎么写
2013/09/19 职场文书
小学生操行评语
2014/04/22 职场文书
大学教师师德师风演讲稿
2014/08/22 职场文书
幼儿园六一活动总结
2014/08/27 职场文书
2014年村党支部工作总结
2014/12/04 职场文书
幼儿园综治宣传月活动总结
2015/05/07 职场文书
爱国影片观后感
2015/06/18 职场文书
小学生大队委竞选稿
2015/11/20 职场文书
Pandas数据结构之Series的使用
2022/03/31 Python
开发微信小程序之WXSS样式教程
2022/04/18 HTML / CSS