深入理解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 相关文章推荐
Mootools 1.2 手风琴(Accordion)教程
Sep 15 Javascript
IFrame跨域高度自适应实现代码
Aug 16 Javascript
JavaScript中把数字转换为字符串的程序代码
Jun 19 Javascript
jQuery+ajax实现鼠标单击修改内容的方法
Jun 27 Javascript
基于JS实现回到页面顶部的五种写法(从实现到增强)
Sep 03 Javascript
微信小程序 转发功能的实现
Aug 04 Javascript
实现一个完整的Node.js RESTful API的示例
Sep 29 Javascript
antd Upload 文件上传的示例代码
Dec 14 Javascript
微信小程序+腾讯地图开发实现路径规划绘制
May 22 Javascript
javascript自定义日期比较函数用法示例
Jul 22 Javascript
vue动态禁用控件绑定disable的例子
Oct 28 Javascript
VUE动态生成word的实现
Jul 26 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
PHP基于SMTP协议实现邮件发送实例代码
2017/04/27 PHP
PHP5.0 TIDY_PARSE_FILE缓冲区溢出漏洞的解决方案
2018/10/14 PHP
php在linux环境中如何使用redis详解
2020/12/15 PHP
JavaScript国旗变换效果代码
2008/08/13 Javascript
csdn 博客的css样式 v3
2009/02/24 Javascript
JavaScript获取onclick、onchange等事件值的代码
2013/07/22 Javascript
JS控制日期显示的小例子
2013/11/23 Javascript
AngularJs根据访问的页面动态加载Controller的解决方案
2015/02/04 Javascript
javascript删除数组重复元素的方法汇总
2015/06/24 Javascript
AngularJS 执行流程详细介绍
2016/08/18 Javascript
Jquery 整理元素选取、常用方法一览表
2016/11/26 Javascript
Bootstrap下拉菜单Dropdowns的实现代码
2017/03/17 Javascript
详解在vue-cli中使用路由
2017/09/25 Javascript
VUE2.0+Element-UI+Echarts封装的组件实例
2018/03/02 Javascript
微信小程序chooseImage的用法(从本地相册选择图片或使用相机拍照)
2018/08/22 Javascript
记一次Vue.js混入mixin的使用(分权限管理页面)
2019/04/17 Javascript
在element-ui的select下拉框加上滚动加载
2019/04/18 Javascript
vue中使用props传值的方法
2019/05/08 Javascript
JS实现简单tab选项卡切换
2019/10/25 Javascript
JavaScript设计模式之门面模式原理与实现方法分析
2020/03/09 Javascript
[01:38]2018DOTA2亚洲邀请赛主赛事第二日现场采访 神秘商人痛陈生计不易
2018/04/05 DOTA
[58:11]守擂赛第二周擂主赛 DeMonsTer vs Leopard
2020/04/28 DOTA
二种python发送邮件实例讲解(python发邮件附件可以使用email模块实现)
2013/12/03 Python
从零学Python之hello world
2014/05/21 Python
Python+Pika+RabbitMQ环境部署及实现工作队列的实例教程
2016/06/29 Python
python+selenium开发环境搭建图文教程
2017/08/11 Python
对python调用RPC接口的实例详解
2019/01/03 Python
python正则爬取某段子网站前20页段子(request库)过程解析
2019/08/10 Python
Python安装tar.gz格式文件方法详解
2020/01/19 Python
Python接口测试结果集实现封装比较
2020/05/01 Python
潘多拉珠宝英国官方网上商店:PANDORA英国
2018/06/12 全球购物
医院办公室主任职责
2013/12/29 职场文书
2015年大学元旦晚会活动策划书
2014/12/09 职场文书
离婚协议书范文2014(夫妻感情破裂)
2014/12/14 职场文书
迎新生欢迎词
2015/01/23 职场文书
小学数学教师研修感悟
2015/11/18 职场文书