我們知道,javascript在執行期時是由內到外執行指令碼的,那麼離我們的指令碼最遠的全域對象,很可能要跨越幾層範圍才能訪問到它。不過在IE中,從最內層到最外層要花的時間比其他多出很多。加之,javascript是一種膠水語言,它必須要調用DOM對能完成我們大多數選擇。最著名的就是選擇元素(document.getElementById,document.getElementsByTagName,docuemnt.evaluate,document.querySelector),建立元素(document.createElement),此外還有document.body,document.defaultView.getComputedStyle等等,頻繁地調用document對象,但是document是位於window對象下,因此這路程就更遠了。就了提速,我們必須把它們儲存在一個本地變數,那麼每次就省得它長途跋涉了。這種技術的運用明顯體現在jQuery的源碼中:
(function( window, undefined ) {// Define a local copy of jQueryvar jQuery = function( selector, context ) {// The jQuery object is actually just the init constructor 'enhanced'return new jQuery.fn.init( selector, context );},// Map over jQuery in case of overwrite_jQuery = window.jQuery,// Map over the $ in case of overwrite_$ = window.$,// Use the correct document accordingly with window argument (sandbox)document = window.document, //====================省================= }// Expose jQuery to the global objectwindow.jQuery = window.$ = jQuery;})(window);
把window傳進閉包內,就省得它每次都往外找window了。
再看其他類庫
//Raphael window.Raphael = (function () { var separator = /[, ]+/, elements = /^(circle|rect|path|ellipse|text|image)$/, doc = document, win = window,//************略**************
//dojod.global = this;
//ExtDOC = document,
//YUI//************略************ } else if (i == 'win') { c[i] = o[i].contentWindow || o[i]; c.doc = c[i].document;//************略************Y.config = { win: window || {}, doc: document,
但是如果你沒有引入類庫,如果讓IE的javascript跑得更快些呢?用一個變數把它儲存起來?在日本部落格看到一種很厲害的劫持技術,偷龍轉鳳把全域變數document變成一個局部變數。
/*@cc_on _d=document;eval('var document=_d')@*/
<br /><!doctype html><br /><html dir="ltr" lang="zh-CN"><br /> <head><br /> <meta charset="utf-8"/><br /> <title>javascript提速技術 by 司徒正美</title></p><p> <script type="text/javascript"></p><p>var date = new Date;<br />for (var i = 0; i </p><p><button type="button" class="runcode" title="runcode1">運行代碼</button></p><p>運用提速技術後:</p><p> <textarea id="runcode2" style="width:75%" rows="10"><br /><!doctype html><br /><html dir="ltr" lang="zh-CN"><br /> <head><br /> <meta charset="utf-8"/><br /> <title>javascript提速技術 by 司徒正美</title></p><p> <script type="text/javascript"><br /> /*@cc_on _d=document;eval('var document=_d')@*/</p><p>var date = new Date;<br />for (var i = 0; i </p><p><button type="button" class="runcode" title="runcode2">運行代碼</button></p><p>經測試,用了提速技術後,IE的效能比較</p><table class="filament_table" cellspacing="0" width="700" rules="cols"><col class="yellow" width="24%"><col class="grey" width="15%"><col class="yellow"><col class="grey" width="26%"><thead><tr><th colspan="4">IE6</th></tr><tr><th></th><th>document</th><th>document.getElementById</th><th>document.title</th></tr></thead><tbody><tr><td>沒有使用提速技術</td><td>485</td><td>1110 </td><td>1219</td></tr><tr><td>使用提速技術後</td><td>109</td><td>609 </td><td>656</td></tr></tbody></table><table class="filament_table" cellspacing="0" width="700" rules="cols"><col class="yellow" width="24%"><col class="grey" width="15%"><col class="yellow"><col class="grey" width="26%"><thead><tr><th colspan="4">IE8</th></tr><tr><th></th><th>document</th><th>document.getElementById</th><th>document.title</th></tr></thead><tbody><tr><td>沒有使用提速技術</td><td>468 </td><td>797 </td><td>843</td></tr><tr><td>使用提速技術後</td><td>78 </td><td>328 </td><td>407</td></tr></tbody></table><p>我們看一下實現原理:</p><pre class="brush:javascript;gutter:false;toolbar:toolbar:false">document; doc; //很明顯,調用這個比直接document快,document還要鑽進window內部找一番 </pre><p>如何劫持它呢?</p><pre class="brush:javascript;gutter:false;toolbar:toolbar:false">var doc = document;var document = doc; </pre><p>這樣明顯不行因為在先行編譯階段,var變數會提前,上面代碼相當於</p><pre class="brush:javascript;gutter:false;toolbar:toolbar:false">var docvar document //這裡被劫持了doc = document //注意,document已經變成undefineddocument = doc //相當於window.undefined = undefined </pre><p>沒有辦法,只好在執行期才定義這個document變數,javascript的動態解析技術派上用場了,eval就是其代表之一。</p><pre class="brush:javascript;gutter:false;toolbar:toolbar:false">var doc = document;eval('var document = doc'); </pre><p>為了讓IE專用,用了IE特有的條件編譯。</p><pre class="brush:javascript;gutter:false;toolbar:toolbar:false">/*@cc_on var doc = document;eval('var document = doc');@*/ </pre><p>嘛,window的東西其實蠻多,我們一一把它們變成本地變數又如何?</p><pre class="brush:javascript;gutter:false;toolbar:toolbar:false">/*@cc_oneval((function(props) { var code = []; for (var i = 0 l = props.length;i<l;i++){ var prop = props[i]; window['_'+prop]=window[prop]; code.push(prop+'=_'+prop) } return 'var '+code.join(',');})('document event body location title self top parent alert setInterval clearInterval setTimeout clearTimeout'.split(' ')));@*/ </pre><p>我們可以再擴充一下,讓其更多全域變數或全域方法局部化。不過經驗測,FF使用它會報錯,chrome則慢了,其他瀏覽器不明顯。</p><pre class="brush:javascript;gutter:false;toolbar:toolbar:false"> if( !+"\v1" ){ var code = [],ri = 0,prop,str = "var " for(var a in window) code[ri++] = a; for (var i = 0 ,n = code.length;i<n;i++){ var prop = code[i] window['_'+prop] = window[prop]; str += prop+'=_'+prop+"," } str = str.slice(0,-1); eval(str) } </pre><p> <textarea id="runcode3" style="width:75%" rows="10"><br /><!doctype html><br /><html dir="ltr" lang="zh-CN"><br /> <head><br /> <meta charset="utf-8"/><br /> <title>javascript提速技術 by 司徒正美</title></p><p> <script type="text/javascript"><br /> var __chrome = navigator.userAgent.indexOf("Chrome") !== -1;<br /> var __firefox = !!window.Components</p><p> if( !__chrome & !__firefox ){</p><p> var code = [],ri = 0,prop,str = "var "<br /> for(var a in window)<br /> code[ri++] = a;<br /> for (var i = 0 ,n = code.length;i<n;i++){<br /> var prop = code[i]<br /> window['_'+prop] = window[prop];<br /> str += prop+'=_'+prop+","<br /> }<br /> str = str.slice(0,-1);<br /> eval(str)<br /> }<br />var date = new Date;<br />for (var i = 0; i </p><p><button type="button" class="runcode" title="runcode3">運行代碼</button></p><p>