深入理解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 相关文章推荐
几种设置表单元素中文本输入框不可编辑的方法总结
Nov 25 Javascript
node.js中的fs.createReadStream方法使用说明
Dec 17 Javascript
Jquery数字上下滚动动态切换插件
Aug 08 Javascript
jQuery垂直多级导航菜单代码分享
Aug 18 Javascript
js无提示关闭浏览器窗口的两种方法分析
Nov 06 Javascript
jQuery中值得注意的trigger方法浅析
Dec 12 Javascript
vue通过路由实现页面刷新的方法
Jan 25 Javascript
详解vue中的父子传值双向绑定及数据更新问题
Jun 13 Javascript
微信小程序实现下拉刷新动画
Jun 21 Javascript
vue页面加载时的进度条功能(实例代码)
Jan 13 Javascript
深入理解webpack process.env.NODE_ENV配置
Feb 23 Javascript
Vue指令实现OutClick的示例
Nov 16 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
ThinkPHP V2.2说明文档没有说明的那些事实例小结
2015/07/01 PHP
PHP操作mysql数据库分表的方法
2016/06/09 PHP
JavaScript DOM 学习第五章 表单简介
2010/02/19 Javascript
解决jquery异步按一定的时间间隔刷新问题
2012/12/10 Javascript
ajaxFileUpload.js插件支持多文件上传的方法
2014/09/02 Javascript
JS实现的竖向折叠菜单代码
2015/10/21 Javascript
jquery.validate 自定义验证方法及validate相关参数
2016/01/18 Javascript
js简单倒计时实现代码
2016/04/30 Javascript
原生javascript 学习之js变量全面了解
2016/07/14 Javascript
javascript实现瀑布流动态加载图片原理
2016/08/12 Javascript
详解JavaScript的内置对象
2016/12/07 Javascript
深入理解JS继承和原型链的问题
2016/12/17 Javascript
js仿微信公众平台打标签功能
2017/04/08 Javascript
Angular弹出模态框的两种方式
2017/10/19 Javascript
vue小白入门教程
2018/04/02 Javascript
layer弹出层 iframe层去掉滚动条的实例代码
2018/08/17 Javascript
ES6知识点整理之数组解构和字符串解构的应用示例
2019/04/17 Javascript
js Array.slice的8种不同用法示例
2019/07/10 Javascript
使用python获取CPU和内存信息的思路与实现(linux系统)
2014/01/03 Python
用Python实现QQ游戏大家来找茬辅助工具
2014/09/14 Python
Python2.x版本中cmp()方法的使用教程
2015/05/14 Python
浅析Python中的for 循环
2016/06/09 Python
Python初学者需要注意的事项小结(python2与python3)
2018/09/26 Python
python 搭建简单的http server,可直接post文件的实例
2019/01/03 Python
基于python和flask实现http接口过程解析
2020/06/15 Python
Python如何使用神经网络进行简单文本分类
2021/02/25 Python
Waterford英国官方网站:世界上最受欢迎的优质水晶品牌
2019/08/17 全球购物
领导接待方案
2014/03/13 职场文书
奥林匹克的口号
2014/06/13 职场文书
员工激励培训演讲稿
2014/09/16 职场文书
2014年财务工作自我评价
2014/09/23 职场文书
中学教师个人总结
2015/02/10 职场文书
《半截蜡烛》教学反思
2016/02/19 职场文书
基于Go Int转string几种方式性能测试
2021/04/28 Golang
Python Parser的用法
2021/05/12 Python
Linux中各个目录的作用与内容
2022/06/28 Servers