JavaScript惰性函数定义

Posted 安慕希

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript惰性函数定义相关的知识,希望对你有一定的参考价值。

函数是js世界的一等公民,js的动态性、易变性在函数的应用上,体现的淋漓尽致。做为参数,做为返回值等,正是函数这些特性,使得js开发变的有趣。

下面就阐述一下,js一个有趣的应用--惰性函数定义(Lazy Function Definition)。

惰性载入表示函数执行的分支只会在函数第一次掉用的时候执行,在第一次调用过程中,该函数会被覆盖为另一个按照合适方式执行的函数,这样任何对原函数的调用就不用再经过执行的分支了。

下面我们看几个典型的例子:

 1 function addEvent (type, element, fun) {
 2     if (element.addEventListener) {
 3         element.addEventListener(type, fun, false);
 4     }
 5     else if(element.attachEvent){
 6         element.attachEvent(‘on‘ + type, fun);
 7     }
 8     else{
 9         element[‘on‘ + type] = fun;
10     }
11 }

上面是注册函数监听的各浏览器兼容函数。由于,各浏览之间的差异,不得不在用的时候做能力检测。显然,单从功能上讲,已经做到了兼容浏览器。

美中不足,每次绑定监听,都会对能力做一次检测。然而,真正的应用中,这显然是多余的,同一个应用环境中,其实只需要检测一次即可。

 

下面我们重写上面的addEvent:

 1 function addEvent (type, element, fun) {
 2     if (element.addEventListener) {
 3         addEvent = function (type, element, fun) {
 4             element.addEventListener(type, fun, false);
 5         }
 6     }
 7     else if(element.attachEvent){
 8         addEvent = function (type, element, fun) {
 9             element.attachEvent(‘on‘ + type, fun);
10         }
11     }
12     else{
13         addEvent = function (type, element, fun) {
14             element[‘on‘ + type] = fun;
15         }
16     }
17     return addEvent(type, element, fun);
18 }

由上,第一次调用addEvent会对浏览器做能力检测,然后,重写了addEvent。下次再调用的时候,由于函数被重写,不会再做能力检测。

 

同样的应用,javascript高级程序设计里的一例子:

 1 function createXHR(){
 2     if (typeof XMLHttpRequest != "undefined"){
 3         return new XMLHttpRequest();
 4     } else if (typeof ActiveXObject != "undefined"){
 5         if (typeof arguments.callee.activeXString != "string"){
 6             var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0",
 7                             "MSXML2.XMLHttp"];
 8     
 9             for (var i=0,len=versions.length; i < len; i++){
10                 try {
11                     var xhr = new ActiveXObject(versions[i]);
12                     arguments.callee.activeXString = versions[i];
13                     return xhr;
14                 } catch (ex){
15                     //skip
16                 }
17             }
18         }
19     
20         return new ActiveXObject(arguments.callee.activeXString);
21     } else {
22         throw new Error("No XHR object available.");
23     }
24 }

很显然,惰性函数在这里优势更加明显,因为这里有更多的分支。下面我们看一下重写后台的函数:

 1 function createXHR() {
 2             if (typeof XMLHttpRequest != "undefined") {
 3                 createXHR = function () {
 4                     return new XMLHttpRequest();
 5                 }
 6                 return new XMLHttpRequest();
 7             } else if (typeof ActiveXObject != "undefined") {
 8                 var curxhr;
 9                 var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0",
10                     "MSXML2.XMLHttp"];
11 
12                 for (var i = 0, len = versions.length; i < len; i++) {
13                     try {
14                         var xhr = new ActiveXObject(versions[i]);
15                         curxhr = versions[i];
16                         createXHR = function () {
17                             return new ActiveXObject(curxhr);
18                         }
19                         return xhr;
20                     } catch (ex) {
21                         //skip
22                     }
23                 }
24             } else {
25                 throw new Error("No XHR object available.");
26             }
27         }

浏览器之间最大的差异,莫过于Dom操作,Dom操作也是前端应用 中最频繁的操作,前端的大多性能提升,均体现在Dom操作方面。

下面看一个Dom操作方面的惰性函数定义例子:

 1 var getScrollY = function() {
 2 
 3     if (typeof window.pageYOffset == ‘number‘) {
 4 
 5         getScrollY = function() {
 6             return window.pageYOffset;
 7         };
 8 
 9     } else if ((typeof document.compatMode == ‘string‘) &&
10                (document.compatMode.indexOf(‘CSS‘) >= 0) &&
11                (document.documentElement) &&
12                (typeof document.documentElement.scrollTop == ‘number‘)) {
13 
14         getScrollY = function() {
15             return document.documentElement.scrollTop;
16         };
17 
18     } else if ((document.body) &&
19                (typeof document.body.scrollTop == ‘number‘)) {
20 
21       getScrollY = function() {
22           return document.body.scrollTop;
23       }
24 
25     } else {
26 
27       getScrollY = function() {
28           return NaN;
29       };
30 
31     }
32 
33     return getScrollY();
34 }

惰性函数定义应用还体现在创建单例上:

 1 unction Universe() {
 2 
 3     // 缓存的实例
 4     var instance = this;
 5 
 6     // 其它内容
 7     this.start_time = 0;
 8     this.bang = "Big";
 9 
10     // 重写构造函数
11     Universe = function () {
12         return instance;
13     };
14 }

当然,像上面这种例子有很多。惰性函数定义,应用场景我们可以总结一下:

1 应用频繁,如果只用一次,是体现不出它的优点出来的,用的次数越多,越能体现这种模式的优势所在;

2 固定不变,一次判定,在固定的应用环境中不会发生改变;

3 复杂的分支判断,没有差异性,不需要应用这种模式;

以上是关于JavaScript惰性函数定义的主要内容,如果未能解决你的问题,请参考以下文章

VSCode自定义代码片段12——JavaScript的Promise对象

VSCode自定义代码片段12——JavaScript的Promise对象

JavaScript设计模式与开发实践:惰性函数

从延迟处理讲起,JavaScript 也能惰性编程?

JavaScript 惰性实例化代码

Javascriptg高级函数