深入理解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 相关文章推荐
JavaScript中的Math 使用介绍
Apr 21 Javascript
javascript的创建多行字符串的7种方法
Apr 29 Javascript
Js 正则表达式知识汇总
Dec 02 Javascript
jQuery插件pagewalkthrough实现引导页效果
Jul 05 Javascript
jQuery中通过ajax调用webservice传递数组参数的问题实例详解
May 20 Javascript
浅谈FastClick 填坑及源码解析
Mar 02 Javascript
linux 后台运行node服务指令方法
May 23 Javascript
小程序数据通信方法大全(推荐)
Apr 15 Javascript
基于vue实现一个神奇的动态按钮效果
May 15 Javascript
vue项目中自定义video视频控制条的实现代码
Apr 26 Javascript
jQuery实现视频展示效果
May 30 jQuery
jQuery实现手风琴特效
Jan 11 jQuery
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
关于时间计算的结总
2006/12/06 PHP
PHP中“简单工厂模式”实例代码讲解
2012/09/04 PHP
PHP递归遍历文件夹去除注释并压缩php源代码的方法示例
2018/05/23 PHP
thinkPHP5框架路由常用知识点汇总
2019/09/15 PHP
很好用的js日历算法详细代码
2013/03/07 Javascript
JavaScript类属性的访问方式详解
2014/02/11 Javascript
Bootstrap编写一个兼容主流浏览器的受众门户式风格页面
2016/07/01 Javascript
js日期相关函数dateAdd,dateDiff,dateFormat等介绍
2016/09/24 Javascript
JS针对Array的各种操作汇总
2016/11/29 Javascript
JS实现Ajax的方法分析
2016/12/20 Javascript
JavaScript获取URL参数的方法之一
2017/03/24 Javascript
Vue实现选择城市功能
2017/05/27 Javascript
vue2.0全局组件之pdf详解
2017/06/26 Javascript
vue组件表单数据回显验证及提交的实例代码
2018/08/30 Javascript
微信小程序框架wepy之动态控制类名
2018/09/14 Javascript
vue-cli 构建骨架屏的方法示例
2018/11/08 Javascript
使用Angular Cli如何创建Angular私有库详解
2019/01/30 Javascript
小程序实现新用户判断并跳转激活的方法
2019/05/20 Javascript
python单例模式实例分析
2015/04/08 Python
Python判断文件和文件夹是否存在的方法
2015/05/21 Python
Python多线程和队列操作实例
2015/06/21 Python
python程序封装为win32服务的方法
2021/03/07 Python
Python帮你微信头像任意添加装饰别再@微信官方了
2019/09/25 Python
Python3 中作为一等对象的函数解析
2019/12/11 Python
python pyqtgraph 保存图片到本地的实例
2020/03/14 Python
Python flask框架实现浏览器点击自定义跳转页面
2020/06/04 Python
python爬虫快速响应服务器的做法
2020/11/24 Python
OpenCV灰度化之后图片为绿色的解决
2020/12/01 Python
使用canvas对多图片拼合并导出图片的方法
2018/08/28 HTML / CSS
Otticanet意大利:最顶尖的世界名牌眼镜, 能得到打折季的价格
2019/03/10 全球购物
采购员的工作职责
2013/12/26 职场文书
学生打架检讨书1000字
2014/01/16 职场文书
信用卡逾期证明示例
2014/09/13 职场文书
2014财务人员自我评价范文
2014/09/21 职场文书
副校长2015年教育教学工作总结
2015/07/27 职场文书
python使用opencv对图像添加噪声(高斯/椒盐/泊松/斑点)
2022/04/06 Python