JavaScript 函数自覆盖模式

来源:互联网 发布:js在线运行工具 编辑:程序博客网 时间:2024/05/16 08:02

如果一个函数中有不少局部变量,而且并非 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