深入理解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 相关文章推荐
通过AJAX的JS、JQuery两种方式解析XML示例介绍
Sep 23 Javascript
jquery统计复选框选中示例
Nov 05 Javascript
jquery表单验证框架提供的身份证验证方法(示例代码)
Dec 27 Javascript
js判断当前浏览器类型,判断IE浏览器方法
Jun 02 Javascript
jquery中append()与appendto()用法分析
Nov 14 Javascript
纯JS实现只能输入数字的简单代码
Jun 21 Javascript
为什么使用koa2搭建微信第三方公众平台的原因
May 16 Javascript
JavaScript设计模式之缓存代理模式原理与简单用法示例
Aug 07 Javascript
详解小程序输入框闪烁及重影BUG解决方案
Aug 31 Javascript
JS无限级导航菜单实现方法
Jan 05 Javascript
基于Nuxt.js项目的服务端性能优化与错误检测(容错处理)
Oct 23 Javascript
vue实现信息管理系统
May 30 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
第四节 构造函数和析构函数 [4]
2006/10/09 PHP
PHP防止跨域提交表单
2013/11/01 PHP
单台服务器的PHP进程之间实现共享内存的方法
2014/06/13 PHP
yii2.0框架场景的简单使用示例
2020/01/25 PHP
jQuery 页面载入进度条实现代码
2009/02/08 Javascript
js/jQuery对象互转(快速操作dom元素)
2013/02/04 Javascript
js获取当前路径的简单示例代码
2014/01/08 Javascript
JS自调用匿名函数具体实现
2014/02/11 Javascript
浅谈javascript的分号的使用
2015/05/12 Javascript
基于jQuery实现返回顶部实例代码
2016/01/01 Javascript
详解Bootstrap glyphicons字体图标
2016/01/04 Javascript
全面理解JavaScript中的闭包
2016/05/12 Javascript
jQuery动态移除和添加背景图片的方法详解
2017/03/07 Javascript
使用cropper.js裁剪头像的实例代码
2017/09/29 Javascript
教你用Cordova打包Vue项目的方法
2017/10/17 Javascript
基于vue2实现左滑删除功能
2017/11/28 Javascript
基于axios封装fetch方法及调用实例
2018/02/05 Javascript
vue插槽slot的理解和使用方法
2019/04/03 Javascript
深入浅析Vue 中 ref 的使用
2019/04/29 Javascript
vue中的 $slot 获取插槽的节点实例
2019/11/12 Javascript
微信小程序canvas动态时钟
2020/10/22 Javascript
Python2中的raw_input() 与 input()
2015/06/12 Python
python实现图片彩色转化为素描
2019/01/15 Python
利用Python的turtle库绘制玫瑰教程
2019/11/23 Python
Django中文件上传和文件访问微项目的方法
2020/04/27 Python
python使用nibabel和sitk读取保存nii.gz文件实例
2020/07/01 Python
matplotlib部件之套索Lasso的使用
2021/02/24 Python
英国家喻户晓的高街品牌:River Island
2017/11/28 全球购物
美国在线打印网站:Overnight Prints
2018/10/11 全球购物
西安当代医院管理研究院笔试题
2015/12/11 面试题
读书之星事迹材料
2014/05/12 职场文书
主持人开幕词
2015/01/29 职场文书
春节慰问信范文
2015/02/15 职场文书
男生贾里读书笔记
2015/06/30 职场文书
关于远足的感想
2015/08/10 职场文书
Mysql数据库中datetime、bigint、timestamp来表示时间选择,谁来存储时间效率最高
2021/08/23 MySQL