《改善JavaScript程序的188个建议(71-78)》由会员分享,可在线阅读,更多相关《改善JavaScript程序的188个建议(71-78)(19页珍藏版)》请在金锄头文库上搜索。
1、建议71:推荐分支函数分支函数解决的一个问题是浏览器Z间兼容性的重复判断。解决浏览器Z间的 兼容性的一般方式是使用if逻辑来进行特性检测或能力检测,根据浏览器不同的实 现来实现功能上的兼容,这样做的问题是,每执行一次代码,可能都需要进行一次 浏览器兼容性方面的检测,这是没有必要的。能占在代码初始化执行的时候就检测 浏览器的兼容性,在Z后的代码执行过稈中,就无须再进行检测了呢?答案是:能。分支技术就可以解决这个问题,下面以声明一个XMLHttpRequest 实例对象为例进行介绍。var XHR = functionO var standard = createXHR : function()
2、return new XMLHttpRequest();var newActionXObject = createXHR : function() return new ActionXObject (z,Msxml2. XMLHTTPZ,);var oldActionXObject = createXHR : function() return new ActionXObject(Microsoft. XMLHTTP);if(standard. createXHR() return standard; else try newActionXObjcct. createXHR();return
3、newActionXObject; catch(o) oldActionXObject. createXHR();return oldActionXObject;();从上面的例了可以看出,分支的原理就是:声明几个不同名称的对彖,但为这 些对彖声明一个名称相同的方法(这是关键)。这些不同的对象,却拥有相同的方 法,根据不同的浏览器设计各自的实现,接肴开始进行一次浏览器检测,并且由浏 览器检测的结果来决定返冋哪一个对象,这样不论返冋的是哪一个对彖,最后名称 相同的方法部作为对外一致的接口。这是在JavaScript运行期间进行的动态检测,将检测的结果返冋赋值给其他 的对象,并且提供相同的接口,这
4、样存储的对象就可以使用名称相同的接口了。其 实,恰性载入函数跟分支函数在原理上是非常相近的,只是在代码实现方面有并异。建议72:惰性载入函数悄性载入函数主要解决的问题也是兼容性,原理跟分支函数类似,下面是简单 的示例。var addEvent = function(el, type, handie) addEvent = el. addEventListcncr ? function(el, type, handie) el. addEventListener(type, handie, false); : function(el, type, handie) el. attachEvent(
5、on + type, handie);;/在第一次执行addEvent函数时,修改了 dddEvcnt函数Z后,必须执行一次 addEvent(cl, type, handie);从代码上看,悄性载入函数也是在函数内部改变白身的一种方式,这样在重复 执行的时候就不会再进行兼容性方面的检测了。惰性载入表示函数执行的分支仅会发生一次,即第一次调用的时候。在第一次 调用的过稈中,该函数会被覆盖为另一个按合适方式执行的函数,这样任何对原函 数的调用都不用再经过执行的分支了。其优点如下:要执行的适当代码只有在实际调用函数时才执行。尽管第一次调用该函数会因额外的第二个函数调用而稍微慢点,但麻续的调用 都会
6、很快,因为避免了多重条件。由于浏览器之间的行为差异,多数JavaScript代码包含了大量的if语句,将 执行引导到正确的代码中。在下面悄性载入的createXHRO中,if语彳U的每个分支都会为createXHRO变 量赋值,有效覆盖了原有的函数,最示一步便是调用新赋函数。下次调用createXHRO 的时候,就会真接调用被分配的函数,这样就不用再次执行if语句。function createXHRO if( typeof XMLHttpRequest != undefined) return new XMLHttpRequest(); else if( typeof ActiveXObje
7、ct != undefined*) if( typeof arguments. callee. activeXString != string) ver versions = /?MSXML2. XMLHttp, /ZMSXML2. XMLHttp. 3. 0,MSXML2. XMLHttp. 6. 0;for(var i = 0, len 二 versions. length; i len; i+) try var xhr = new ActiveXObject. (versionsi);arguments, calleeactiveXString = versionsi; retum xh
8、r; catch(ex) /跳过return new ActiveXObject(arguments. callee, activeXString); else throw new Error(z,No XHR object available.,z);每一次调用createXHRO时都要对浏览器所支持的功能仔细检杳,这样每次调) createXHRO时都要进行相同的测试就变得没有必要了。减少if语句使其不必每 一次都执行,代码就会执行得快些。解决方案就是幡性载入的技巧。function createXHRO if( typeof XMLHttpRequest != undefined) cr
9、eateXHR = function() return new XMLHttpRequest();; else if( typeof ActiveXObject !二undefined*) createXHR = function() if( typeof arguments. callee, activeXString != string) verversions二MSXML2. XMLHttp, “MSXML2. XMLHttp. 3. 0, MSXML2. XMLHttp. 6. 0;for(var i = 0, len = versions. length; i len; i+) tr
10、y var xhr = new ActiveXObject(versionsi);arguments, callee. activeXString 二 versionsi; return xhr; catch(ex) /跳过return new ActiveXObject(arguments. callee, activeXStrimg);; else createXHR = function() throw new Error(z,No XIIR object available.?,);;retum createXHR ();如前面所述,if语句的每一个分支都会为createXHR变最赋值
11、,有效覆盖了原 有函数。最麻一步便绘调川新赋函数,下次调JU creatXHR()的时候就会直接调川被 分配的函数,这样就不用再次执行if语句。建议73:函数绑定有价值函数绑定就是为了纠正函数的执行上下文,特别是当函数中带有Ihis关键字 的时候,这一点尤其重要,稍微不小心,就会使函数的执行上下文发生跟预期不同 的改变,导致代码执行上的错误。函数绑定具有3个特征:函数绑是要创建一个函数,可以在特足环境中以指泄参数调用另一个函数。一个简单的bindO函数接收一个函数和一个环境,返冋一个在给定环境中调用 给泄函数的函数,并且将所有参数原封不动地传递过去。被绑定函数与普通函数相比有更多的开销,它们需
12、要更多内存,同时也因为多 重函数调用而稍微慢一点,最好只在必要时使用。第一个特征常常和冋调函数及事件处理函数一起使用。var htindler = message : Event hsndlecf ,handleClick : function(event) alert (this .message);var bln 二 document getElementByld (iny-btn);EventUti1.addHandler (btn, click, handier handledick); /undefined出现上述结果的原因在于没有保存handler. handleClick()环境
13、(上下文环 境),所以this对象最后指向了 DOM按钮而非handler。可以使用闭包修正此问题: var htindler = message : Event hsndlecf ,handleClick : function(event) alert (this .message);var bln 二 document getElementByld (iny-btn);EventUti1. addHandler(btn, click, function(event) handler handleClick(event););这是特定于这段代码的解决方案。创建多个闭包可能会令代码变得难于理解
14、和 调试,因此,很多JavaScript库实现了一个可以将函数绑定到指定环境的函数 bindO。bind()函数的功能是提供一个可选的执行上下文传递给函数,并且在bindO 函数内部返冋一个函数,以纠正在函数调用上出现的执行上下文发生的变化。最容 易出现的错误就是冋调函数和事件处理程序一起使用。function bind(fn, context) retum functionO return fn.apply(context, arguments);;在bindO中创建一个闭包,该闭包使用apply调用传入的参数,并为apply 传递context对彖和参数。注意:这里使用的arguments
15、对象是内部函数的,而非bind()的。在调用返回 的函数时,会在给定的环境中执行被传入的函数并给出所有参数。var handler = message : Eve nt. handled,handledick : function(event) alert (this, message);;var btn 二 document. getElementByld(my-btn);EventUti1. addlkmdlerbtn, click, bind(handler, handlerClick, handler);建议74:使用高阶函数高阶函数作为函数式编程众多风格中的一项显著特征,经常被使用。实际上, 高阶函数即对函数的进一步抽象。高阶函数至少满足下列条件Z-:接受函数作为输入。输出一个函数。在函数式语言中,函数不但是