JavaScript 函数自覆盖模式

如果一个函数中有不少局部变量,而且并非 primitive type 的,意味着在执行该函数的时候占用较多的内存开销。这一过程是显然易见的,例如执行这个函数 1000 次,就要重复创建那些局部变量 1000 次——这真是一个多余的过程。再者,如果函数逻辑不会去修改局部变量的值,即属于 constant / final 修饰的值,那么显然,我们仅仅创建一次变量便足够了。好,既然如此,我们把这些可以优化的变量都放置函数体外面好了。虽然 js 没有 constant / final 的修饰符,不过即使如此,那只会仅仅影响到程序的可读性这点不好。为优化这点,我们只需把变量的声明写到函数体外,不要写在函数里面。

有两点应注意:

  1. 你可选择不用局部变量,而是可以将变量写成 public 属性的调用方式,作用无异。但本文考虑的是基于替代局部变量的私有方式;
  2. 当然,这种优化不必然强制的,如果遇到是的简单的字符串,int……,那么小 case 写在函数体内倒无妨,解释器处理很快,再优化可能要差别不大。总之得看情况,千万别养成强迫症哦。

于是,我们需要考虑把这些 constant 放在何处合理的地方。通常会想到是一个闭包:

;(function(){
	var regExp = /d/; // 提取变量声明语句
	window.isNumber = function(v){
	    // var regExp = /d/;
            return regExp.test(v);
	}
})();

以上是一个简单的例子,就目的来说已经可以达到前面所说之要求了。我们利用一个闭包去存储私有变量,这些私有变量是可以被返回的函数访问的,但在这段代码外面则访问不到了。但问题是,若我们不想用闭包呢?那是一个“匿名函数”(反对使用闭包,其实也说不上究竟有什么不好,反正觉得多了一层“怪怪”的——纯属个人感观而言)。

这里,我们可以大胆使用“覆盖函数”的方式——竟然“覆盖”?是的,别以为“覆盖了就没了”是一件很危险的事哦:P,请注意我们这里是"巧用"覆盖。

以下就是一个例子:

/**
 * 固定位置元素。el必须为绝对定位。
 * @param {HTMLElement} el
 * @param {Boolean}  isOnTop 是否在最上方的,false=最下方
 */
$$.dhtml.fixedLayer = function(el, isOnTop){
        var body  = window.document.body;
        var floor = window.Math.floor;
        
        $$.dhtml.fixedLayer = function (el, isOnTop){
                var lastScrollY = isOnTop ? -20 : -(window.innerHeight - el.clientHeight - 30); /* 调整 CSS Bottom 的值 */
                window.setInterval(function(){
                        var percent = body.scrollTop - lastScrollY; // 移动的步伐是多大?
                        percent = shiftMove(percent);

                        if (percent == 0){
                                return; // 0表示不滚动,位置不变,所以DOM不作变化
                        }else{
                                lastScrollY += percent; // 保存偏移的位置,可正可负
                                addTop(el, percent);
                        }
                }, 10);
        }
        
        /**
         * stype.top 带单位的,运算时不方便,写一个函数处理吧
         * @private
         * @param {HTMLElement} el
         * @param {Number} amount
         * @return {Number} 增加 amount 后此时元素的 top 值
         */
        function addTop(el, amount){
                var top = window.parseInt(el.style.top) || 0; // style.top 有时为空字符,那就是 = 0
                top += amount;  // 弱类型的表现,先是int类型的+=
                top += 'px';    // 然后这是 string 类型的!
                el.style.top = top;
                
                return top;
        }
        
        /**
         * 为更加平滑,缩小移动的步伐。
         * @private
         * @param {Number} percent
         * @return {Number}
         */
        function shiftMove(percent){
                percent = 0.2 * percent;
                percent = floor(percent); // 取整数
                
                return percent;
        }
        
        return $$.dhtml.fixedLayer(el, isOnTop);
}
这种的方式特点是创函数逻辑在函数内一层,第一次执行函数会覆盖原定义的函数(被覆盖的函数是外一层,完成了函数签名档作用)。函数自己覆盖掉自己,但函数名字依旧不变,所以这一切对外如何如何调用都是透明的。如果不调用方法,函数的逻辑并不执行,颇有点类 lazyExecute 意味。

对于 hash 对象的写法,也就是存在冒号 :  的写法,相应的处理如 lifesinger 所示:

    createElement: function(sHtml) {
        // ...
        var createElement = function(sHtml) {
            // ...
        };
        this.createElement = createElement;
        return createElement(sHtml);
    }

该模式的一个缺点是,如果要重命名函数名称,比不使用该模式多一次的操作。

实不相瞒,小弟当时也是受 lifesinger 在 zbm2001 博文之留言所启发而至的。源地址如下:

《自定义createElement——根据html字符串创建元素》http://zbm2001.iteye.com/blog/510627


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sp42a

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值