深入理解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 相关文章推荐
jquery特效 幻灯片效果示例代码
Jul 16 Javascript
JQuery实现动态表格点击按钮表格增加一行
Aug 24 Javascript
JS组件Bootstrap实现弹出框和提示框效果代码
Dec 08 Javascript
JavaScript设计模式初探
Jan 07 Javascript
基于jquery实现简单的分页控件
Mar 17 Javascript
利用JS实现点击按钮后图片自动切换的简单方法
Oct 24 Javascript
浅谈JavaScript的innerWidth与innerHeight
Oct 12 Javascript
浅谈Vue数据绑定的原理
Jan 08 Javascript
element-ui upload组件多文件上传的示例代码
Oct 17 Javascript
使用 electron 实现类似新版 QQ 的登录界面效果(阴影、背景动画、窗体3D翻转)
Oct 23 Javascript
微信小程序保存图片到相册权限设置
Apr 09 Javascript
详解Webpack4多页应用打包方案
Jul 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
php下实现农历日历的代码
2007/03/07 PHP
PHP下几种删除目录的方法总结
2007/08/19 PHP
PHP将DateTime对象转化为友好时间显示的实现代码
2011/09/20 PHP
php跨站攻击实例分析
2014/10/28 PHP
php验证身份证号码正确性的函数
2016/07/20 PHP
PHP PDOStatement::bindColumn讲解
2019/01/30 PHP
JavaScript中的私有成员
2006/09/18 Javascript
javascript 动态加载 css 方法总结
2009/07/11 Javascript
IE 当eval遇上function的处理
2011/08/09 Javascript
javascript 全选与全取消功能的实现代码
2012/12/23 Javascript
JS实现判断滚动条滚到页面底部并执行事件的方法
2014/12/18 Javascript
JavaScript计算两个日期时间段内日期的方法
2015/03/16 Javascript
js实现鼠标经过表格行变色的方法
2015/05/12 Javascript
JS实现三个层重叠点击互相切换的方法
2015/10/06 Javascript
Javascript控制div属性动态变化实例分析
2015/10/08 Javascript
通过npm引用的vue组件使用详解
2017/03/02 Javascript
JavaScript观察者模式(publish/subscribe)原理与实现方法
2017/03/30 Javascript
JavaScript无操作后屏保功能的实现方法
2017/07/04 Javascript
jquery动态赋值id与动态取id方法示例
2017/08/21 jQuery
JS实现延迟隐藏功能的方法(类似QQ头像鼠标放上展示信息)
2017/12/28 Javascript
JavaScript动态加载重复绑定问题
2018/04/01 Javascript
JavaScript this使用方法图解
2020/02/04 Javascript
基于element-ui对话框el-dialog初始化的校验问题解决
2020/09/11 Javascript
微信小程序实现单个或多个倒计时功能
2020/11/01 Javascript
Eclipse + Python 的安装与配置流程
2013/03/05 Python
在PyCharm中实现关闭一个死循环程序的方法
2018/11/29 Python
Python实现把多维数组展开成DataFrame
2019/11/30 Python
Django:使用filter的pk进行多值查询操作
2020/07/15 Python
HTML5 UTF-8 中文乱码的解决方法
2013/11/18 HTML / CSS
canvas实现高阶贝塞尔曲线(N阶贝塞尔曲线生成器)
2018/01/10 HTML / CSS
美国汽车性能部件和赛车零件网站:Vivid Racing
2018/03/27 全球购物
荷兰最大的儿童服装店:The Kids Republic
2019/04/13 全球购物
时尚、社区、科技:SEVENSTORE
2019/04/26 全球购物
战略合作意向书范本
2014/04/01 职场文书
《认识年月日》教学反思
2016/02/19 职场文书
Python 机器学习工具包SKlearn的安装与使用
2021/05/14 Python