深入理解JavaScript系列(50):Function模式(下篇)


Posted in Javascript onMarch 04, 2015

介绍

本篇我们介绍的一些模式称为初始化模式和性能模式,主要是用在初始化以及提高性能方面,一些模式之前已经提到过,这里只是做一下总结。

立即执行的函数

在本系列第4篇的《立即调用的函数表达式》中,我们已经对类似的函数进行过详细的描述,这里我们只是再举两个简单的例子做一下总结。

// 声明完函数以后,立即执行该函数

(function () {

    console.log('watch out!');

} ());
//这种方式声明的函数,也可以立即执行

!function () {

    console.log('watch out!');

} ();
// 如下方式也都可以哦

~function () { /* code */ } ();

-function () { /* code */ } ();

+function () { /* code */ } ();

立即执行的对象初始化

该模式的意思是指在声明一个对象(而非函数)的时候,立即执行对象里的某一个方法来进行初始化工作,通常该模式可以用在一次性执行的代码上。

({

    // 这里你可以定义常量,设置其它值

    maxwidth: 600,

    maxheight: 400,
    //  当然也可以定义utility方法

    gimmeMax: function () {

        return this.maxwidth + "x" + this.maxheight;

    },
    // 初始化

    init: function () {

        console.log(this.gimmeMax());

        // 更多代码...

    }

}).init();  // 这样就开始初始化咯

分支初始化

分支初始化是指在初始化的时候,根据不同的条件(场景)初始化不同的代码,也就是所谓的条件语句赋值。之前我们在做事件处理的时候,通常使用类似下面的代码:

var utils = {

    addListener: function (el, type, fn) {

        if (typeof window.addEventListener === 'function') {

            el.addEventListener(type, fn, false);

        } else if (typeof document.attachEvent !== 'undefined') {

            el.attachEvent('on' + type, fn);

        } else {

            el['on' + type] = fn;

        }

    },

    removeListener: function (el, type, fn) {

    }

};

我们来改进一下,首先我们要定义两个接口,一个用来add事件句柄,一个用来remove事件句柄,代码如下:

var utils = {

    addListener: null,

    removeListener: null

};

实现代码如下:
if (typeof window.addEventListener === 'function') {

    utils.addListener = function (el, type, fn) {

        el.addEventListener(type, fn, false);

    };

} else if (typeof document.attachEvent !== 'undefined') { // IE

    utils.addListener = function (el, type, fn) {

        el.attachEvent('on' + type, fn);

    };

    utils.removeListener = function (el, type, fn) {

        el.detachEvent('on' + type, fn);

    };

} else { // 其它旧浏览器

    utils.addListener = function (el, type, fn) {

        el['on' + type] = fn;

    };

    utils.removeListener = function (el, type, fn) {

        el['on' + type] = null;

    };

}

用起来,是不是就很方便了?代码也优雅多了。

自声明函数

一般是在函数内部,重写同名函数代码,比如:

var scareMe = function () {

    alert("Boo!");

    scareMe = function () {

        alert("Double boo!");

    };

};

这种代码,非常容易使人迷惑,我们先来看看例子的执行结果:
// 1. 添加新属性

scareMe.property = "properly";

// 2. scareMe赋与一个新值

var prank = scareMe;

// 3. 作为一个方法调用

var spooky = {

    boo: scareMe

};

// 使用新变量名称进行调用

prank(); // "Boo!"

prank(); // "Boo!"

console.log(prank.property); // "properly"

// 使用方法进行调用

spooky.boo(); // "Boo!"

spooky.boo(); // "Boo!"

console.log(spooky.boo.property); // "properly"

通过执行结果,可以发现,将定于的函数赋值与新变量(或内部方法),代码并不执行重载的scareMe代码,而如下例子则正好相反:
// 使用自声明函数

scareMe(); // Double boo!

scareMe(); // Double boo!

console.log(scareMe.property); // undefined

大家使用这种模式时,一定要非常小心才行,否则实际结果很可能和你期望的结果不一样,当然你也可以利用这个特殊做一些特殊的操作。

内存优化

该模式主要是利用函数的属性特性来避免大量的重复计算。通常代码形式如下:

var myFunc = function (param) {

    if (!myFunc.cache[param]) {

        var result = {};

        // ... 复杂操作 ...

        myFunc.cache[param] = result;

    }

    return myFunc.cache[param];

};
// cache 存储

myFunc.cache = {};

但是上述代码有个问题,如果传入的参数是toString或者其它类似Object拥有的一些公用方法的话,就会出现问题,这时候就需要使用传说中的hasOwnProperty方法了,代码如下:
var myFunc = function (param) {

    if (!myFunc.cache.hasOwnProperty(param)) {

        var result = {};

        // ... 复杂操作 ...

        myFunc.cache[param] = result;

    }

    return myFunc.cache[param];

};
// cache 存储

myFunc.cache = {};

或者如果你传入的参数是多个的话,可以将这些参数通过JSON的stringify方法生产一个cachekey值进行存储,代码如下:
var myFunc = function () {

    var cachekey = JSON.stringify(Array.prototype.slice.call(arguments)),

        result;

    if (!myFunc.cache[cachekey]) {

        result = {};

        // ... 复杂操作 ...

        myFunc.cache[cachekey] = result;

    }

    return myFunc.cache[cachekey];

};
// cache 存储

myFunc.cache = {};

或者多个参数的话,也可以利用arguments.callee特性:
var myFunc = function (param) {

    var f = arguments.callee,

        result;

    if (!f.cache[param]) {

        result = {};

        // ... 复杂操作 ...

        f.cache[param] = result;

    }

    return f.cache[param];

};
// cache 存储

myFunc.cache = {};

总结

就不用总结了吧,大家仔细看代码就行咯

Javascript 相关文章推荐
js实现动态添加、删除行、onkeyup表格求和示例
Aug 18 Javascript
JavaScript中实现异步编程模式的4种方法
Sep 24 Javascript
JavaScript中的lastIndexOf()方法使用详解
Jun 06 Javascript
jQuery ajax提交Form表单实例(附demo源码)
Apr 06 Javascript
基于JS实现移动端向左滑动出现删除按钮功能
Feb 22 Javascript
Angular利用trackBy提升性能的方法
Jan 26 Javascript
微信小程序通过保存图片分享到朋友圈功能
May 24 Javascript
如何解决React官方脚手架不支持Less的问题(小结)
Sep 12 Javascript
JavaScript模板引擎应用场景及实现原理详解
Dec 14 Javascript
Vue 列表上下过渡效果的实例代码
Jun 25 Javascript
在vue项目中使用sass语法问题
Jul 18 Javascript
使用Vue实现简单计算器
Feb 25 Javascript
深入探讨javascript中的数据类型
Mar 04 #Javascript
深入理解JavaScript系列(49):Function模式(上篇)
Mar 04 #Javascript
js实现百度联盟中一款不错的图片切换效果完整实例
Mar 04 #Javascript
jQuery中大家不太了解的几个方法
Mar 04 #Javascript
深入理解JavaScript系列(48):对象创建模式(下篇)
Mar 04 #Javascript
js计算德州扑克牌面值的方法
Mar 04 #Javascript
深入理解JavaScript系列(47):对象创建模式(上篇)
Mar 04 #Javascript
You might like
《雄兵连》《烈阳天道》真的来了
2020/07/13 国漫
php小偷相关截取函数备忘
2010/11/28 PHP
Yii清理缓存的方法
2016/01/06 PHP
Zend Framework自定义Helper类相关注意事项总结
2016/03/14 PHP
PHP批量修改文件名称的方法分析
2017/02/27 PHP
PHP保留两位小数的几种方法
2019/07/24 PHP
javascript学习笔记(二) js一些基本概念
2012/06/18 Javascript
在Node.js中实现文件复制的方法和实例
2014/06/05 Javascript
深入理解Javascript中this的作用域
2014/08/12 Javascript
innerHTML在IE中报错解决方案
2014/12/15 Javascript
JS实现图片高亮展示效果实例
2015/11/24 Javascript
使用bootstrap-paginator.js 分页来进行ajax 异步分页请求示例
2017/03/09 Javascript
jQuery接受后台传递的List的实例详解
2017/08/02 jQuery
AngularJs导出数据到Excel的示例代码
2017/08/11 Javascript
浅谈JsonObject中的key-value数据解析排序问题
2017/12/06 Javascript
详解react关于事件绑定this的四种方式
2018/03/09 Javascript
vue展示dicom文件医疗系统的实现代码
2018/08/27 Javascript
vue引入axios同源跨域问题
2018/09/27 Javascript
Vue 全家桶实现移动端酷狗音乐功能
2018/11/16 Javascript
通过JQuery,JQueryUI和Jsplumb实现拖拽模块
2019/06/18 jQuery
解析原来浏览器原生支持JS Base64编码解码
2019/08/12 Javascript
JavaScript事件委托实现原理及优点进行
2020/08/29 Javascript
JavaScript实现网页计算器功能
2020/10/29 Javascript
[19:24]DOTA2客户端使用指南 一分钟快速设置轻松超神
2013/09/24 DOTA
[57:22]2018DOTA2亚洲邀请赛 4.7总决赛 LGD vs Mineski 第五场
2018/04/10 DOTA
python应用程序在windows下不出现cmd窗口的办法
2014/05/29 Python
python3批量删除豆瓣分组下的好友的实现代码
2016/06/07 Python
判断Threading.start新线程是否执行完毕的实例
2020/05/02 Python
python如何利用Mitmproxy抓包
2020/10/10 Python
HTML5 script元素async、defer异步加载使用介绍
2013/08/23 HTML / CSS
美国奢侈品购物平台:Orchard Mile
2018/05/02 全球购物
机械专业应届生求职信
2013/09/21 职场文书
学生就业推荐信
2013/11/13 职场文书
高一英语教学反思
2014/01/22 职场文书
中层干部竞聘演讲稿
2014/05/15 职场文书
建筑安全责任书范本
2014/07/24 职场文书