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