學(xué)習(xí)札記筆記深入理解javascript系列_第1頁
學(xué)習(xí)札記筆記深入理解javascript系列_第2頁
學(xué)習(xí)札記筆記深入理解javascript系列_第3頁
學(xué)習(xí)札記筆記深入理解javascript系列_第4頁
學(xué)習(xí)札記筆記深入理解javascript系列_第5頁
已閱讀5頁,還剩560頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

編寫高質(zhì)量JavaScript代碼的基本要 (2)命名函數(shù)表達(dá) 全面解析Module模 立即調(diào)用的函數(shù)表達(dá) 強(qiáng)大的原型和原型 (6)S.O.L.I.D五大原則之單一職責(zé) (7)S.O.L.I.D五大原則之開閉原則 (8)S.O.L.I.D五大原則之里氏替換原則 根本沒有“JSON對象”這回事 JavaScript(晉級高手必讀篇 執(zhí)行上下文(Execution 變量對象(Variable This?Yes, 作用域鏈(Scope 函數(shù) 閉包 面向?qū)ο缶幊讨话憷?面向?qū)ο缶幊讨瓻CMAScript實 求值策 《你真懂JavaScript嗎?》答案詳 (21)S.O.L.I.D五大原則之接口原則 (22)S.O.L.I.D五大原則之依賴倒置原則 JavaScript與DOM(上)——也適用于新 JavaScript與DOM(下 設(shè)計模式之單例模 設(shè)計模式之構(gòu)造函數(shù)模 設(shè)計模式之建造者模 設(shè)計模式之工廠模 設(shè)計模式之裝飾者模 設(shè)計模式之外觀模 設(shè)計模式之模 設(shè)計模式之觀察者模 設(shè)計模式之策略模 設(shè)計模式之命令模 設(shè)計模式之迭代器模 設(shè)計模式之中介者模 設(shè)計模式之享元模 設(shè)計模式之職責(zé)鏈模 設(shè)計模式之適配器模 設(shè)計模式之組合模 設(shè)計模式之模板方 設(shè)計模式之原型模 設(shè)計模式之狀態(tài)模 設(shè)計模式之橋接模 代碼復(fù)用模式(避免篇 代碼復(fù)用模式(推薦篇 對象創(chuàng)建模式(上篇 對象創(chuàng)建模式(下篇 Function模式(上篇 Function模式(下篇 (結(jié)局篇 編寫高質(zhì)量JavaScript深入理解JavaScript系列文章,包括了,翻譯,,整理等各類型文章,來源 才華橫溢的StoyanStefanov,在他寫的由O’Reilly初版的新書《JavaScriptPatterns》(JavaScript模式)中,要是為我們的讀者貢獻(xiàn)其 妙的事情。具體一點就是編寫高質(zhì)量JavaScript的一些要素,例如避免全局變量,使用單變量,在循環(huán)中預(yù)緩存length(長度),遵循代碼閱讀,以及。此也包括一些與代碼不太相關(guān)的習(xí)慣,但對整體代碼的創(chuàng)建關(guān),包括撰寫API文檔、執(zhí)行評審以及運(yùn)行JSLint。這些習(xí)慣和最佳做法可以幫助你寫出更好MaintainableCode)軟件bug的修復(fù)是昂貴的,并且隨著時間的推移,這些bug的成本也會增加,尤其當(dāng)這些bugbug的時候就立即修他任務(wù),忘了那個特定的代碼,一段時間后再去查看這些代碼就需要:bug(且發(fā)現(xiàn)bug和修復(fù)bug的不是同一個人)。因此,必須降低理解代碼花費的時線(營業(yè)收入)和開發(fā)人員的,因為我們更應(yīng)該去開發(fā)新的激動人心的事物而不這就要求你的進(jìn)行進(jìn)行,修改,和調(diào)整。例如:bug是程序在新的環(huán)境下工作(例如,市場上出現(xiàn)新想瀏覽器可的代碼意味著最小全局變量(MinimizingJavaScript通過函數(shù)管理作用域。在函數(shù)內(nèi)部的變量只在這個函數(shù)內(nèi)部,函數(shù)外每個JavaScript環(huán)境有一個全局對象,當(dāng)你在任意的函數(shù)外面使用this的時候可以見,該全局對象有個附加屬性叫做windowwindow(通常)指向該全局對象本身。下面的代碼片段顯示了如何在瀏覽器環(huán)境中創(chuàng)建和的全局變量:myglobalmyglobal=o";console.log(myglobal);// console.log(window.myglobal);//" console.log(window["myglobal"]);//" console.log(this.myglobal);// 全局變量的問題在于,你的JavaScript應(yīng)用程序和web頁面上的所有代碼都共享了web第的JavaScript方的代第用戶和分析代比方說,該第定義了一個全局變量,叫做result;接著,在你的函數(shù)中也定義一個名為result的全局變量。其結(jié)果就是后面的變量覆蓋前面的,第就一但是要想讓全局變量少最重要的還是始終使用var來變量。由于JavaScript可以甚至不需要就可以使用變量;第二,JavaScript有隱含的全局概念,意味著functionfunctionsum(x,y)result=x+y;returnresult;}此段代碼中的result沒有。代碼照樣運(yùn)作正常,但在調(diào)用函數(shù)后你最后的結(jié)果經(jīng)驗法則是始終使用var變量,正如改進(jìn)版的sum()函數(shù)所演示的functionfunctionsum(x,y){varresult=x+y;returnresult;}另一個創(chuàng)建隱式全局變量的反例就是使用任務(wù)鏈進(jìn)行部分var。下面的片段中a是本地變量但是b//反例,勿使用functionfoo//反例,勿使用functionfoovara=b=0;//}此現(xiàn)象發(fā)生的原因在于這個從右到左的賦值,首先,是賦值表達(dá)式b=0,此情況下b是未的。這個表達(dá)式的返回值是0,然后這個0就分配給了通過var定義的這個局部變量a。換句話說,就好比你輸入了:varvara=(b=functionfunctionfoo(){vara,b;a=b0}忘記varSideEffectsWhenForgettingvar)delete通過var(任何函數(shù)之外的程序中創(chuàng)建)無var(無視是否在函數(shù)中創(chuàng)建)性。屬性是可以通過delete操作符刪除的,而變量是不能的://定義三個全局變量varglobal_var=1;global_novar//定義三個全局變量varglobal_var=1;global_novar2(function(){global_fromfunc=3;deleteglobal_var;//falsedeleteglobal_novar;//truedeleteglobal_fromfunc;//truetypeofglobal_var;//"number"typeofglobal_novar;//"undefined"typeofglobal_fromfunc;//在ES5嚴(yán)格模式下,未的變量(如面的代碼片段中的兩個)工作時全局對象(AccesstotheGlobalObject)在瀏覽器中,全局對象可以通過window屬性在代碼的任何位置(除非你做了些比較出格的事情,像是了一個名為window的局部變量)。但是在其他環(huán)境在沒有硬編碼的window標(biāo)識符下全局對象,你可以在任何層級的函數(shù)作用域varvarglobal=(function(){returnthis;new),thisECMAScript5JavaScript遞一個指向this作為你即時函數(shù)的參數(shù)。單var(Singlevar在函數(shù)頂部使用單varfunctionfunc(){vara=1,functionfunc(){vara=1,b=sum=a+b,myobject={},//function}您可以使用一個var語句多個變量,并以逗號分隔。像這種初始化變量同時初始undefined)和增加代碼的可讀性。在你看到代碼后,你可以根據(jù)初始化的值你也可以在的時候做一些實際的工作,例如前面代碼中的sum=a+b這個情況,另外一個例子就是當(dāng)你使用DOM(文檔對象模型)時,你可以使用單一的var把DOM一起指定為局部變量,就如下面代碼所示的:functionfunctionupdateElement()varelstyle=//使用el和style}預(yù)解析:varAProblemwithScatteredJavaScript中,你可以在函數(shù)的任何位置多個var語句,并且它們就好像是在函數(shù)頂部一樣發(fā)揮作用,這種行為稱為hoisting(懸置/置頂解析/預(yù)解析)。當(dāng)你JavaScript,只要你的變量是在同一個作用域中(同一函數(shù)),它都被當(dāng)做是的,即使是它在var前使用的時候??聪旅孢@個例子myname"globalfunctionfunc()alert(myname);//"undefined"varmyname="local";alert(myname);//"local"}}在這個例子中,你可能會以為第一個alert”global出”loacl”。這種期許是可以理解的,因為在第一個alert的時候,myname未聲明,此時函數(shù)肯定很自然而然地看全局變量myname,但是,實際上并不是這么工作的。第一個alert會彈出”undefined”是因為myname被當(dāng)做了函數(shù)的局部變量這種混亂,最好是預(yù)先你想使用的全部變量。mynamemyname="global";//globalvariablefunctionfunc(){varmynamevarmynameundefined;alert(myname);//"undefined"myname="local";alert(myname);//"local"}下文的階段。第二個階段是代碼執(zhí)行,函數(shù)表達(dá)式和不合格的標(biāo)識符(為的這種ECMAScript標(biāo)準(zhǔn)中并未定義,通常用來描述行為。forfor在for循環(huán)中,你可以循環(huán)取得數(shù)組或是數(shù)組類似對象的值,譬如argumentsHTMLCollectionfor(vari=0;i<myarray.length;i++)//使用myarray[i}代碼,尤其當(dāng)myarray不是數(shù)組,而是一個HTMLCollection對象的時候。HTMLCollections指的是DOM HTMLCollections,這些是在DOM.images:.images:.links:所有 元.forms.forms[0].elements集合的麻煩在于它們實時查詢基本文檔(HTML頁面)。這意味著每次你任何集合的長度,你要實時查詢DOM,而DOM操作一般都是比較昂貴的。forfor(vari=0,max=myarray.length;i<max;i++)//使用myarray[i}HTMLCollections,2(Safari3)到190倍(IE7)之間。//zxx:此數(shù)據(jù)貌似很老,參注意到,當(dāng)你明確想要修改循環(huán)中的集合的時候(例如,添加的DOM元素),伴隨著單varfunctionfunctionlooper(){vari=0,myarray=[];//for(i=0,max=myarray.length;i<max;i++)//使用myarray[i}}var數(shù),你不得不去確定你能夠把i和max引入新的函數(shù)(如果在這里沒有用的話,最后一個需要對循環(huán)進(jìn)行調(diào)整的是使用下面表達(dá)式之一來替換iii=i+1i+=1JLnt–-sietrns)”。zx:這里比較難翻譯,本意應(yīng)該是讓代碼變得更加的棘手如果你直接無視它,JLntpuspusase(默認(rèn)是daut)。少了一個變量(無000vari,myarray=for(i=myarray.length;i–-;)//使用myarray[i}whilevarmyarray=i=myarray.length;while(i–-){//使用myarray[i}這些小的改進(jìn)只體現(xiàn)在性能上,此外JSLint會對使用ifor-infor-infor-infor-infor-in(因為JavaScript),但外,在for-in(序列)是不能保證的。所以最好數(shù)組使用正常的for循環(huán),對象使用for-in循環(huán)。hasOwnPropertyvarman={hands:2,legs:heads:if(typeofOtotype.clone==="undefined"){Ototype.clone=function(){};}man的對象。在man成后的某個地方,在對象原型上增加了一個很有用的名叫clone()的方法。此原型鏈?zhǔn)菍崟r的,這就意味著所有的對象自動可以新的方法。為了避免枚舉man的時clonehasOwnProperty過濾,會導(dǎo)致clone()函數(shù)顯示出來,在大多數(shù)情況下這是不希望出現(xiàn)的。////for-infor(variinman)ifman.hasOwnProperty(iconsole.log(i,":",}}/*hands:legs:headsheads:// //for-inloopwithoutcheckinghasOwnProperty()for(variinman){console.log(i,":",}hands:legs:heads:clone:hasOwnProperty的形式是取消Ototypeforfor(variinman)ifOtotype.hasOwnProperty.call(man,iconsole.log(i,":",}}其好處在于在man對象重新定義hasOwnProperty情況下避免命名。也避免了varvari,hasOwn=Ototype.hasOwnProperty;for(iinman){ifhasOwn.call(man,iconsole.log(i,":",}}}嚴(yán)格來說,不使用hasOwnProperty()并不是一個錯誤。根據(jù)任務(wù)以及你對代(和其原型鏈)不確定的時候,添加hasOwnProperty()更加些格式化的變化(通不過JSLint)if//警告:通不過//警告:通不過JSLintvarihasOwnOtotype.hasOwnProperty;for(iinman)if(hasOwn.call(man,i)){//過濾console.log(i,":",}AugmentingBuilt-in擴(kuò)增構(gòu)造函數(shù)的prototype增加內(nèi)置的構(gòu)造函數(shù)原型(如Object(),Array(),或Function())挺的,但是這嚴(yán)可能更期望使用內(nèi)置的JavaScript方法來持續(xù)不斷地工作,而不是你另加的方法。hasOwnProperty可以預(yù)期將來的ECMAScript版本或是JavaScript置方法來實現(xiàn)。例如,你可以添加ECMAScript5中描述的方法,一直到各個現(xiàn)或已經(jīng)是你支持的瀏覽器JavaScript引擎部分。ifif(typeofOtoype.myMethod!=="function"){Otoype.myMethod=function(){}switch(switch你可以通過類似下面形式的switchvarvarinspect_me=0,result='';switch(inspect_me){case0:result="zero";caseresult="one";resultresult=}case和switch(花括號縮進(jìn)規(guī)則除外casecase以break避免貫穿(故意忽略break)。如果你非常確信貫穿是最好的方法,務(wù)必記錄以default結(jié)束switchImpliedTypecasting)JavaScript的變量在比較的時候會隱式類型轉(zhuǎn)換。這就是為什么一些諸如:false==0或“”==0返回的結(jié)果是true。為避免引起的隱含類型轉(zhuǎn)換,在你比較值和varvarzero=if(zero===false)//不執(zhí)行,因為zero0,而不是}if(zero==false)}typofJLnt(避免(Avoiding如果你現(xiàn)在的代碼中使用了eval(),記住該語“eval()是”。此方法接受任意的字符串,并當(dāng)作JavaScript代碼來處理。當(dāng)有問題的代碼是事先知道的(不是運(yùn)行時確定的),沒有理由使用eval()。如果代碼是在運(yùn)行時動態(tài)生成,有一個更好的方式不使用eval而達(dá)到同樣的目標(biāo)。例如,用方括號表示法來動態(tài)屬性會更好更varproperty=alert(eval("obj."+varproperty=使用eval()也帶來了安全隱患,因為被執(zhí)行的代碼(例如從網(wǎng)絡(luò)來)可能已被篡改。這是個很常見的,當(dāng)處理Ajax請求得到的JSON相應(yīng)的時候。在這些情況下,最好使用JavaScript內(nèi)置方法來解析JSON不支持JSON.parse(),你可以使用來自JSON.org的庫。同樣重要的是要記住,給setInterval(),setTimeout()和Function()構(gòu)造函數(shù)傳遞字符串,大部分情況下,與使用eval()是類似的,因此要避免。在幕后,JavaScriptsetTimeout("myFunc()",setTimeout("myFunc(1,setTimeout("myFunc(1,2,3)",//更好的setTimeout(myFunc1000);setTimeout(function(){myFunc(1,2,3);},使用新的Function()構(gòu)造就類似于eval(),應(yīng)接近。這可能是一個強(qiáng)大的構(gòu)造,但往往被誤用。如果你絕對必須使用eval(),你可以考慮使用newFunction()代替。有一個小的潛在好處,因為在新Function()中作代碼評估是在局部函數(shù)作用域中運(yùn)行,所以代碼中任何被評估的通過var種方法來自動全局變量是封裝eval()調(diào)用到一個即時函數(shù)中??紤]下面這個例子,這里僅unconsole.log(typeofun);console.log(typeofun);//"undefined"console.log(typeofdeux);//"undefined"console.log(typeoftrois);//"undefined"varjsstring="varun=1;console.log(un);";eval(jsstring);//logs"1"jsstring="vardeux=2;console.log(deux);";newFunction(jsstring)();//logs"2"jsstring="vartrois=3;console.log(trois);";(function(){}());//logsconsole.log(typeofun);//console.log(typeofconsole.log(typeofdeux);//"undefined"console.log(typeoftrois);//另一間eval()和Function構(gòu)造不同的是eval()可以干擾作用域鏈,而Function()更安分守己些。不管你在哪里執(zhí)行Function(),它只看到全局作用域。所以其能很好的避Function(注意到使用Function和newFunction)(function(){var(function(){varlocal=1;eval("local=3;console.log(local)");//logs"3"console.log(local);//logs"3"(function(){varlocal=1;Function("console.log(typeoflocal);")();//logsConversionswith使用parseInt()你可以從字符串中獲取數(shù)值,該方法接受另一個基數(shù)參數(shù),這經(jīng)常省略,但不應(yīng)該。當(dāng)字符串以”0表單域,在ECMAScript308ECMAScript5中改變了。為了避免和意外的結(jié)果,總是指定基數(shù)參數(shù)。varvarmonth="06",year="09";monthmonth=parseInt(month,10);year=parseInt(year,10);此例中,如果你忽略了基數(shù)參數(shù),如parseInt(year),返回的值將是0,因為“09”8(parseIntyear,8),098+"08+"08Number("08")//這些通??煊趐arseInt(),因為parseInt()方法,顧名思意,不是簡單地解析與轉(zhuǎn)換。但是,如果你想輸入例如“08o”,parseInt()將返回數(shù)字,而其它以NaN編碼規(guī)范(Coding(例如代碼縮進(jìn),是Tab制表符鍵還是space)。如果你是你組織中建議采一些開發(fā)人員更喜歡用tab喜歡的空格數(shù)來顯示TabJSLintdo,while,for,for-in),if,switch,以及對象字面量中的對象屬性。下面的代碼就是使functionfunctionouter(a,b){varc=1,d=if(a>b){inner=function(){return{r:c-}elseinner=function(){return{r:c+}return}花括號{}(Curlyin或是for想象下你有一個只有一條語句的forfor(vari=0;i<10;i+=1)for(vari=0;i<10;i+=1)alert(i+"is"+(i%2?"odd":第二個alert已經(jīng)在循環(huán)之外,縮進(jìn)可能了你。為了長遠(yuǎn)打算,最好總是使用花for(vari=0;i<10;i+=1){}if(true)if(true)}else{}左花括號的位置(Openingifif(true)alert("It's}if{alert("It's}這是因為分號插入機(jī)制(semicoloninsertionmechanism)——JavaScript是不挑剔的,當(dāng)你選擇不使用分號結(jié)束一行代碼時JavaScript會導(dǎo)致麻煩,如當(dāng)你返回對象字面量,而左括號卻在下一行的時候:functionfunc(){name:}}如果你希望函數(shù)返回一個含有name回undefined。前面的代碼等價于:functionfunc(){returnundefined;{name:}}functionfunctionfunc(){return{name:}JavaScript空格(White句號后面會使用間隔。在JavaScript中,你可以按照同樣的邏輯在列表模樣表達(dá)式forforvari0i10i1fori和max):forvari0,max10imax;+=1)分隔數(shù)組項的逗號的后面:vara12,varoa1,b:2};myFunc(ab函數(shù)的花括號的前面:functionmyFunc()函數(shù)表達(dá)式functionvarmyFuncfunction使用空格分開所有的操作符和操作對象是另一個不錯的使用,這意味著在+,-,*,&&||vard=a=b+if(a&&b&&c){d=a%c;a+=}vard=a=b+if(a&&b&&c){d=a%c;a+=d;}函數(shù)、if-elseelse或while命名規(guī)范(NamingJavaScript并沒有類,但有newvaradamvaradam= newfunctionfunctionMyConstructor(){...}functionmyFunction(){...}分隔單詞(Separating對于構(gòu)造函數(shù),可以使用大駝峰式命名法(uppercamelcase),如MyConstructor()lowercamelcase),像是myFunction(),calculateArea()和getFirstName()。有單詞小寫以下劃線連接:例如,first_name,favorite_bands,和 pany_name,這種標(biāo)記法幫你直觀地區(qū)分函數(shù)和其他標(biāo)識——原型和ECMAScript的屬性和方法均使用Camel(正則表達(dá)式對象的lastIndex和ignoreCase屬性)。其它命名形式(Other例如,JavaScript中沒有定義常量的方法(盡管有些內(nèi)置的像Number,varPI=3.14,MAX_WIDTH=800;JavaScript=getName:function()returnthis._getFirst()+''+_getFirst:function()//_getLast:function()//}}getName()就表示公共方法,部分穩(wěn)定的API_getFirst()_getLast對象的使用者這些方法在下一個版本中時不能保證工作的,是不能直接使用的。注意,JSLint有些不鳥下劃線前綴,除非你設(shè)置了noman選項為:false。使用尾下劃線表示私有,如name和gprivate(私有)Firefox和兩個后下劃線表示,如:proto和parent。注釋(Writing性規(guī)定注釋代碼比,代碼的某些部分(如正則表達(dá)式)可能注釋要比代碼多。關(guān)于作者(AbouttheAuthorStoyanStefanov是Yahoo!web開發(fā)人員,多個O'Reilly書籍的作者、投稿者和技 上web開發(fā)的。Stoyan還是smush.it優(yōu)化工具的創(chuàng)造者,YUI貢獻(xiàn)者,雅虎性能優(yōu)化工具YSlow2.0的架構(gòu)設(shè)計師。本文轉(zhuǎn)自 (2)命名函數(shù)表達(dá)JavaScript簡單的說,命名函數(shù)表達(dá)式只有一個用戶,那就是在Debug或者Profiler分析的時在ECMAScript中,創(chuàng)建函數(shù)的最常用的兩個方法是函數(shù)表達(dá)式和函數(shù),兩者期間的區(qū)別是有點暈,因為ECMA規(guī)范只明確了一點:函數(shù)必須帶有標(biāo)示符functionfunction函數(shù)名稱(可選)話,如何判斷是函數(shù)還是函數(shù)表達(dá)式呢?ECMAScript是通過上下文來區(qū)分的,如果functionfoo(){}是作為賦值表達(dá)式的一部分的話,那它就是一個函數(shù)表達(dá)式,如果functionfoo(){}被包含在一個函數(shù)體內(nèi),或者位于程序的最頂部的話,那它就functionfunctionfoo(){}varbarfunctionfoonewfunctionbar(){};//表達(dá)式,因為它是newfunctionbar(){}還有一種函數(shù)表達(dá)式不太常見,就是被括號括住的(functionfoo(){}),他是表達(dá)式的原因是因為括號()是一個分組操作符,它的內(nèi)部只能包含表達(dá)式,我們來看幾個例functionfunctionfoo(functionfootry(varx5var}catch(err)//}你可以會想到,在使用eval對JSON,JSON個圓括號里:eval('('+json+')'),這樣做的原因就是因為分組操作符,也就是這對括號,會讓解析器強(qiáng)制將JSON的花括號解析成表達(dá)式而不是代碼塊。trytry{"x5}}catch(err)//}x5表達(dá)式之前被解析/求值,參考如下例子,函數(shù)fn是在alert之后的,但是在alert執(zhí)行的時候,fn已經(jīng)有定義了:functionfn()return o}firstfunction,而有的瀏覽器返回的卻是第二if(true){functionfoo(){return'first';}}elsefunctionfoo()returnreturn}}varfoo;if(true){foo=function(){return'first';}elsefoo=function(){return}函數(shù)的實際規(guī)則如下_函數(shù)_只能出現(xiàn)在_程序_或_函數(shù)體_內(nèi)。從句法上講,它們不能出現(xiàn)在(塊)({)if、whileforBlock(塊)只能包含Statement語句,而不能包含_函數(shù)_這樣的源元素。另一方面,仔細(xì)看一看規(guī)則也會發(fā)現(xiàn),唯一可能讓_表達(dá)式_出現(xiàn)在Block(塊)中情形,就是讓它作function開頭。而這實際上就是說,_函數(shù)表達(dá)式_同樣也不能出現(xiàn)在Statement語句或Block(塊)中(因為Block(塊)就是由Statement語句構(gòu)成的)。在ECMAScript的語法擴(kuò)展中,有一個是函數(shù)語句,目前只有基于Gecko的瀏覽器薦使用(除非你針對Gecko瀏覽器進(jìn)行開發(fā))。Blockifif(true)functionf(){}else{functionf(){}}ifif(true)functionfoo(){return1;}elsefunctionfoo(){return2;}foo();////注:其它客戶端會將foo//因此,第二個foo2footypeoffoo;//ifif(true)functionfoo(){return1;}else//從來不會走到這里,所以這里的foofunctionfoo(){return2;}typeoffoo;//varfoo;ifvarfoo;if(true)foo=functionfoo(){return1;}elsefoo=functionfoo(){return2;}函數(shù)語句和函數(shù)(或命名函數(shù)表達(dá)式)的字符串表示類似,也包括標(biāo)識符ifif(true)functionfoo(){return1;}String(foo);//functionfoo(){return1;Gecko(Firefox3)中存在一個bug,即functionfoo(){return1;}if(true){functionfoo(){return2;}fooFF31,F(xiàn)F3.5varfoo=function(){return1;};if(true){functionfoo(){return2;}foo函數(shù)表達(dá)式在實際應(yīng)用中還是很常見的,在web開發(fā)中友個常用的模式是基于對某//該代碼來自//該代碼來自GarrettSmith的APEJavascriptlibrary varcontains=(function()vardocEl ifPosition!='undefined')returnfunction(el,b)returnreturnPosition(b)&16)!==}elseif(typeofdocEl.contains!='undefined'){returnfunction(el,b){returnel!==b&&}returnfunction(el,b)if(el===b)returnwhile(el!=b&&(b=b.parentNode)!=null);returnel===b;varbar=functionvarvarf=functionreturntypeoffoo;foofootypeoffoo;//"undefined"f();//"function"functionfunctionfoo(){returnbar();}functionbar(){returnbaz();}functionbaz(){}3//所以當(dāng)調(diào)試器走到debuggerFirebugfoo調(diào)用了bar,bar又調(diào)用了(而fooexpr_test.html),不過,還有一個比較爽地方,就是剛才說的Firebug為表達(dá)式取名的功能:functionfunctionfoo(){returnbar();}varbar=function(){returnbaz();}functionbaz(){}//Callstackbar()functionfunctionfoo(){returnbar();}varbar=if(window.addEventListener){returnfunction(){return}elseif(window.attachEvent){returnfunction(){returnreturn}functionbaz(){}//Callstackfunctionfunctionfoo(){returnbaz();}varbar=function(){varbaz=bar;bar=function(){//Callstack:這時候,調(diào)用棧顯示的是foo調(diào)用了bar,但實際上并非如此,之所以有這種問題,是因為baz和另外一個包含alert('spoofed')的函數(shù)做了交換所導(dǎo)致的?;氐?個函數(shù)的名字都是bar):functionfunctionfoo(){returnbar();}varbar=if(window.addEventListener){returnfunctionbar(){return}elseif(window.attachEvent){returnfunctionbar(){returnbaz();}functionbaz(){}OKJScriptJScript的比較惡的是,IE的ECMAScript實現(xiàn)JScript嚴(yán)重了命名函數(shù)表達(dá)式,搞得現(xiàn)很多人都出來命名函數(shù)表達(dá)式,而且即便是的一版(IE8中使用的5.8版)仍下面我們就來看看IE例1:函數(shù)表達(dá)式的標(biāo)示符到外部作用varf=functiong(){};typeofvarf=functiong(){};typeofg;//"function"上面我們,命名函數(shù)表達(dá)式的標(biāo)示符在外部作用域是無效的,但JScript明顯是了這一規(guī)范,上面例子中的標(biāo)示符g以發(fā)現(xiàn)的bug注:IE9貌似已經(jīng)修復(fù)了這個問例2:將命名函數(shù)表達(dá)式同時當(dāng)作函數(shù)和函數(shù)表達(dá)typeoftypeofg;//"function"varf=functiong(){};特性環(huán)境下,函數(shù)會優(yōu)先于任何表達(dá)式被解析,上面的例子展示的是JScript實際上是把命名函數(shù)表達(dá)式當(dāng)成函數(shù)了,因為它在實際之前就解析了g。3:varvarf=functiong(){};f===g;//falsef.expando='foo';g.expando;//undefined2改f的屬性中保存某個信息,然后想當(dāng)然地通過相同對象的g的同名屬性來使例4:僅僅順序解析函數(shù)而忽略條件語句varvarf=functiong(){return1;if(false)f=functiong(){return2;}g();//這個bug查找就難多了,但導(dǎo)致bug的原因卻非常簡單。首先,g被當(dāng)作函數(shù)解析,由于JScript中的函數(shù)不受條件代碼塊約束,所以在這個很惡的if分中,g被當(dāng)作另一個函數(shù)functiong(){return2},也就是又被了一次。然后,所有“常規(guī)的”表達(dá)式被求值,而此時f被賦予了另一個新創(chuàng)建的對象的。由于在對表達(dá)式求值的時候,不會進(jìn)入“這個可惡if分支,因此f就會繼續(xù)第個函數(shù)functiongreturn1在f中調(diào)用了g,那么將會調(diào)用一個毫不相干的g函數(shù)對象。你可能會文,將不同的對象和arguments.calleevarf=functiong(){return[arguments.callee==f,arguments.calleevarf=functiong(){return[arguments.callee==f,arguments.callee==f();//[true,g();//[false,可以看到,arguments.callee的一直是被調(diào)用的函數(shù),實際上這也是好事,稍后還有一個有趣的例子,那就是在不包含的賦值語句中使用命名函數(shù)表達(dá)式f=function按照代碼的分析,我們原本是想創(chuàng)建一個全局屬性f(注意不要和一般的函數(shù)混淆了,里面用的是帶名字的生命),JScript函數(shù)解析了,所以左邊的f被為局部變量了(和一般的函數(shù)里的一樣),然后在函數(shù)執(zhí)行的時候,f已經(jīng)是定義過的了,右邊的functionf(){}則直接就賦值給局部變量f了,所以f根本就不是全局屬性。了解了JScript這么以后,我們就要及時預(yù)防這些問題了,首先防范標(biāo)識符泄漏那個厭的標(biāo)識符g嗎?——如果我們能夠當(dāng)g不存在,可以避免多少不必要的麻煩哪。因此,關(guān)鍵就在于始終要通過f或者arguments.callee來函數(shù)。如果你JScript知道了這些不符合規(guī)范的代碼解析bugvarvarf=(function(){if(true){returnfunction}returnfunction我們知道,這個函數(shù)調(diào)用返回的函數(shù)(帶有標(biāo)識符g的函數(shù)),然后賦值給了外部的f。我們也知道,命名函數(shù)表達(dá)式會導(dǎo)致產(chǎn)生多余的函數(shù)對象,而該對象與返回的函數(shù)對象不是一回事。所以這個多余的g內(nèi)存問題就出現(xiàn)了。這是因為if語句內(nèi)部的函數(shù)與g是在同一個作用域中被的。這種情況下,除非我們顯式斷開對g函數(shù)的,否則它一直占著內(nèi)存不放。varvarf=(function(){varf,g;if(true)f=function}elsef=function}//設(shè)置g為nullgg=null;return通過設(shè)置g為null,回收器就把g的那個隱式函數(shù)給回收掉了,為了驗證我測試很簡單,就是命名函數(shù)表達(dá)式創(chuàng)建10000個函數(shù),然后把它們保存在一個數(shù)組functionfunctioncreateFn(){return(function(){varf;if(true)f=functionF(){return'standard';}elseif(false)f=functionF(){return'alternative';}elsef=functionF(){return'fallback';}//varF=null;returnf;}vararr=[for(vari=0;i<10000;i++){arr[i]=createFn();}通過運(yùn)行在WindowsXPSP2without`null`: 7.6K->20.3Kwith`null`: 7.6K->18Kwithout`null`: 14K->29.7Kwith`null`: 14K->27K如我們所料,顯示斷開可以釋放內(nèi)存,但是釋放的內(nèi)存不是很多,10000個函數(shù)對象才釋放大約3M的內(nèi)存,這對一些小型不算什么,但對于大型程序,或者長Safari2.x中JS的解析也有一些bug,但介于版本比較低,所以我們在這里就會創(chuàng)建一個特殊的對象在這里,有一點十分有意思,那就是ECMA-262定義這個(保存函數(shù)標(biāo)識符的)“特殊”對象的方式。標(biāo)準(zhǔn)說newObject()表達(dá)式那樣”創(chuàng)建這個對象。如果從字面上來理解這句話,那么這個對象就應(yīng)該是全局Object的一個實例。然SpiderMonkeySpiderMonkeyOtotypeOtotype.xOtotype.x='outer';varx=/*foo殊的對象實際上就是{foo:}。當(dāng)通過作用域鏈解析xfoo的局部環(huán)境。如果沒有找到x,foo:},由于該對象繼承自O(shè)totype,所以在此可以找到x。而這個x的值也就是Ototype.x(outer)。結(jié)果,外部函數(shù)的作用域(包含x='inner'的作用域)就不會被解析了。*/(functionalert(xSpiderMonkey洞。也就是說,“特殊”對象不再繼承Ototype了。不過,如果你使用Firefox3或者更低版本,還可以“重溫”這種行為。另一個把內(nèi)部對象實現(xiàn)為全局Object對象的是黑莓(Blackberry)瀏覽器。目前,它的活動對象(ActivationObject)仍然繼承Ototype。可是,ECMA-262_活動對象_也要“像調(diào)用newObject()表達(dá)式那樣”來創(chuàng)建(或者說像創(chuàng)建保存NFE標(biāo)識符的對象一樣創(chuàng)建)。人家規(guī)范只說了_活動對象_是規(guī)范中的一Ototype.xOtotype.x='outer';varx='inner';/*x在該對象中找不到x??墒?,由于活動對象繼承自O(shè)totype,xOtotype中又確實有x,x包含xinner'的外部函數(shù)的作用域(活動對象)*/alert(x);//顯示:outerOtotypevarconstructor=function(){return1;};constructor((而不是constructor===Ototype.constructor;//truetoString===Ototype.toString;//true//要避免這個問題,要避免使用Ototype里的屬性名稱,如toString,valueOf,hasOwnProperty等等。JScriptvarvarfn=var要//并將 賦值給ifif(true)f=functionF(){}elseif(false)f=functionF(){}elsef=functionF(){}一個與函數(shù)名(標(biāo)識符)對應(yīng)的變量,并賦值為//這實際上是給相應(yīng)標(biāo)識 的函數(shù)對象作了一個標(biāo)記//以 回收器知道可以回收它varF=returnaddEvent1varaddEvent=vardocEl.//var要if(docEl.addEventListener)3fn=functionaddEvent(element,eventName,callback){element.addEventListener(eventName,callback,}}elseif(docEl.attachEvent)fn=functionaddEvent(element,eventName,callback){element.attachEvent('on'+eventName,callback);}}elsefn=functionaddEvent(element,eventName,callback){element['on'+eventName]=callback;}}4)清除由JScript創(chuàng)建的addEvent//一定要保證在賦值前使用var//除非函數(shù)頂部已經(jīng) 了addEventvaraddEvent=null;5returnvarvarhasClassName=varcache={functionhasClassName(element,className)var_className='(?:^|\\s+)'+className+'(?:\\s+|$)';varre=cache[_className]||(cache[_className]=newreturn}returnvarvaraddEvent=vardocEl.function/*...}function/*...}functionfunction/*...}if(typeofdocEl.addEventListener!='undefined'){returnaddEventListener;}elseif(typeofdocEl.attachEvent!='undefined'){returnattachEvent;}return同實現(xiàn)。例如,在調(diào)試器中看到attachEvent,我們就知道addEvent是基于attachEvent的實現(xiàn)。當(dāng)然,基于實現(xiàn)來命名的方式也不一定都行得通。假如我們要提供一個API,并按照這種方式把函數(shù)命名為inner。那么API用戶的很容易就會被相應(yīng)實現(xiàn)的細(xì)節(jié)搞得暈頭轉(zhuǎn)向。'addEvent','addEvent','altAddEvent','addEvent','addEvent2','addEvent_addEventListener','addEvent_attachEvent',N數(shù),等于有N-1的函數(shù)是用不到的。具體來講,如果 addEventListener和addEventAsProperty著內(nèi)存哪;而且,這些內(nèi)存將都得不到釋放,原因跟JScript臭哄哄名表達(dá)WebKit的disWebKit團(tuán)隊在這個問題采取了有點兒另類的策略。介于和命名函數(shù)如此之差 表現(xiàn)力,WebKit 中被顯示在函數(shù)“名稱”的位置上。FranciscoTolmasky詳細(xì)地解釋了這個策略的將來的ECMAScript-2625(目前還是草案)會引入所謂的嚴(yán)格模式(strict性。據(jù)說出于安全方面的考慮,arguments.callee屬性將在嚴(yán)格模式下被“封殺”。因此,在處于嚴(yán)格模式時,arguments.callee會導(dǎo)致TypeError(參見ECMA-262510.6)。而我之所以在此提到嚴(yán)格模式,是因為如果在基5arguments.callee及其bug也就顯得更加重要了。//此前,你可能會使用//此前,你可能會使用arguments.callee(function(x){if(xreturnreturnx*arguments.callee(x-(functionfactorial(x){if(xreturn1;returnx*factorial(x-functionfactorial(x){if(xreturn1;returnx*factorial(x-}理查德·康福德(RichardCornford),是他率先解釋了JScript中命名函數(shù)表達(dá)式所存在的bug。理查德解釋了我在這篇文章中提及的大多數(shù)bug,所以我強(qiáng)烈建議大Yann-ErwanPerio和道格拉斯·克勞克佛德(DouglasCrockford),他們早在2003年就在comp.lang.javascript中提及并討論NFE問題了。約翰-戴維·道爾頓(John-DavidDalton)對“最終解決方案”提出了很好的建議托比·蘭吉的點子被我用在了“替代方案”中(GarrettSmith)和德米特里(DmitrySoshnikov)對英文原文 參考譯文:連接(SpiderMonkey的怪癖之后的章節(jié)參考該文全面解析Module模簡Module模式是JavaScriptModule封裝了變量和functionnamaspace只可用public的方法,其它私有方法全部隱Module模式,最早是由YUI的成員EricMiraglia4從一個簡單的例子來解釋一下基本的用法(一節(jié))基本用varvarCalculator=function(eq) 私有成vareqCtl return add:function(x,y)varval=x+eqCtl.innerHTMLeqCtl.innerHTML=}varvarcalculator=newCalculator('eq');calculator.add(2,2);大家可能看到了,每次用的時候都要newcopy,如果你不需要傳參數(shù)或者沒有一些特殊苛刻的要求的話,我們可以在最后JavaScript(function(function()//...所有的變量和function閉//...但是這里的代碼依然可 外部全局的對注意,函數(shù)后面的括號,這是JavaScript語言所要求的,因為如果你不的話,JavaScript解釋器默認(rèn)是一個function函數(shù),有括號,就是創(chuàng)建一個函數(shù)new:(function(function*JavaScriptJavaScript釋器反向遍歷作用域鏈來查找整個變量的var,如果沒有找到var,解釋器則假(function(function($,YAHOO)//這里,我們的代碼就可以使用全局的jQueryYAHOO}(jQuery,現(xiàn)在很多類都有這種使用方式,比如jQuery源碼可以通過函數(shù)的返回值來返回這個全局變量,這也就是一個基本的Module模varvarblogModule=(function()varmyprivateNamefunctionprivateAddTopic(data)}my.Name=privateName;my.AddTopic=function(data){return}上面的代碼了一個全局變量blogModule,并且?guī)в?個可的屬性:blogModule.AddTopic和blogModule.Name,除此之外,其它代碼都在函數(shù)高級用Module模式的一個限制就是所有的代碼都要寫在一個文件,但是在一些大型項目看看上面的全局參數(shù)導(dǎo)入例子,我們能否把blogModule的,我們先將blogModulevarvarblogModule=(function(my){my.AddPhoto=function(){return}C#里擴(kuò)展方法的感覺?有點類似,但本質(zhì)不一樣哦。同時盡管var不是必須的,但為了確保一致,我們再次使用了它,代碼執(zhí)行以后,blogModule下的AddPhoto就可以使用了,同時函數(shù)內(nèi)部的代碼也依然保證上面的代碼盡管可以執(zhí)行,但是必須先blogModule,然后再執(zhí)行上面的擴(kuò)展代varvarcnblogs=cnblogs||{}cnblogs看看如何利用這個特性來實現(xiàn)Module模式的任意加載順序:varvarblogModule=(function(my)return}(blogModule||序的加載,所以,這個時候的var就是必須要的,因為不,其它文件不ModulevarvarblogModule=(function(my)varoldAddPhotoMethod=my.AddPhoto=function()//重載方法,依然可通過oldAddPhotoMethodreturn}性,你可以調(diào)用oldAddPhotoMethod來用。varvarblogModule=(function(old){varmy={},for(keyinold)if(old.hasOwnProperty(key)){my[key]=old[key];}}varvaroldAddPhotoMethod=old.AddPhoto;my.AddPhoto=function(){//克隆以后,進(jìn)行了重寫,當(dāng)然也可以繼續(xù)調(diào)用return}function根本沒有被,只是對同一個對象多了一種而已,所以如果老對象去改變它,那克隆以后的對象所擁有的屬性或function函數(shù)也會被改變,解決這個問題,我們就得是用遞歸,但遞歸對function函數(shù)的賦值也不好用,所以我們在遞歸的時候eval相應(yīng)的function。不管怎么樣,我還是把這一個方式放在這個帖子里通過上面的例子,我們知道,如果一個module我們非要使用,那怎么辦呢?我們先看一段代碼:varvarblogModule=(function(my)var_private=my._private=my._private||_seal=my._seal=my._seal||function(){deletemy._private;deletemy._seal;deletemy._unseal;_unseal_unseal=my._unseal=my._unseal||function(){my._private=_private;my._seal=_seal;my._unseal=_unseal;return}(blogModule||任何文件都可以對他們的局部變量_private設(shè)屬性,并且設(shè)置對其他的文件也立即生效。一旦這個模塊加載結(jié)束,應(yīng)用會調(diào)用blogModule._seal()"上鎖",這會外部可以調(diào)用_unseal()”開鎖”,然后再加載新文件。加載后再次調(diào)用_seal()”上mentSubModulementSubModule=(function()varmy=//return}總Module

立即調(diào)用的函數(shù)表大家學(xué)JavaScript的時候,經(jīng)常遇到自執(zhí)行函數(shù)的代碼,今天我們主要就來想想 在JavaScript里,任何function在執(zhí)行的時候都會創(chuàng)建一個執(zhí)行上下文,因為為function的變量和function有可能只在該function內(nèi)部,這個上下文,在調(diào)用function的時候,提供了一種簡單的方式來創(chuàng)建自由變量或私有子function。//由于該//由于該functionfunctionfunction由變量//所有說,這個內(nèi)部的function自functionmakeCounter()//只能在makeCountervari=ireturnfunction()}countercounter2ivarcounter=counter();//logs:counter();//logs:varcounter2=counter2();//logs:counter2();//logs:alert(i);錯誤:i沒有defind(因為i是存在于makeCounter內(nèi)部)很多情況下,我們不需要makeCountercase當(dāng)你類似functionfoo(){}或varfoo=function(){}函數(shù)的時候,通過在后面加個括弧就可以實現(xiàn)自執(zhí)行,例如foo(),看代碼:了,比如的function//因為foo僅僅是function(){/*code*/varfoo=function(){/*code*/function(){function(){/*code*/}();//SyntaxError:Unexpectedtoken2function或者function內(nèi)部function關(guān)鍵字的時候,默認(rèn)是認(rèn)為function,而不是function表達(dá)式,如果你不顯示告訴編譯器,它默認(rèn)會成一個缺少名字的function,并且拋出一個語法錯誤信息,因為function需要一個名字。//下面這個//下面這個functionfunctionfoo(){/*code*/}();//SyntaxError:Unexpectedtoken//但是foofunctionfoo(){/*code*/}(1//因為它完全等價于下面這個代碼,一個functionfoo(){/*code*/(1你可以ECMA-262-3indetail.Chapter5.Functions獲取進(jìn)一步的信息為JavaScriptfunction關(guān)鍵字的時候,會將相應(yīng)的代碼解析成function表達(dá)式,而不是function。2(function*code*/(function*code*///由于括弧()和JS&&vari=function(){return10;}true&&function(){/*code*/}();0,function(){/*code*/}();//你甚至可以在function!function(){/*code*/}~function(){/*code*/}-function(){/*code*/}+function(){/*code*/}//還有一個情況,使用newnewfunction(){/*code*/newfunction*code*/和普通function執(zhí)行的時候傳參數(shù)一樣,自執(zhí)行的函數(shù)表達(dá)式也可以這么傳參,因為閉包直接可以傳入的這些參數(shù),利用這些被lock住的傳入?yún)?shù),自執(zhí)行函數(shù)表i從來就沒背lockediiIamlink#10(10個a素的話varelems for(vari=0;i<elems.length;i++)elems[i].addEventListener('click',function(e)alert('Iamlink#'+i);},}//i的值作為locked的索引存在,在循環(huán)執(zhí) ,盡管最后i的值變成a(//但閉包內(nèi)部的lockedInIndexvarelems for(vari=0;i<elems.length;i++)(function(lockedInIndex)elems[i].addEventListener('click',function(e){alert('Iamlink#'+},}//而不是在addEventListenervarelems for(vari=0;i<elems.length;i++)elems[i].addEventListener('click',elems[i].addEventListener('click',(function(lockedInIndex){returnfunction(e){alert('Iamlink#'+})(i),}2個例子里的lockedInIndex變量,也可以換成iiexecutinganonymousfunction),但英文原文作者一直倡議使用立即調(diào)用的函數(shù)表達(dá)式(Immediay-InvokedFunctionExpression)這一名稱,作者又舉了一堆functionfoo(){foo();//必須使用arguments.calleevarfoo=function(){arguments.callee();foo//如果你將foo改變成其它的,你將得到一個used-to-self- 函varfoo=function(){foo();//有些人叫這個是自執(zhí)行的 //有些人叫這個是自執(zhí)行的 (function(){/*code*/}//但一定命名了,這個函數(shù)就不再 的(functionfoo(){/*code*/}(function(){arguments.callee();}(functionfoo(){foo();}5(functionfoo(){foo();}_注:arguments.callee在ECMAScript5strictmodeModule//return一個變量,其中這個變量里包含你 的東//返回的這個變量將賦值給counter,而不是外 的function自varvarcounter=(function(){vari=0;returnget:function(){returni;set:function(val){i=val;increment:function(){return++i;}}counter.get();//0counter.increment();//counter.increment();//counter.iundefinedii i(i關(guān)于Module模式的介紹,請我的上一篇帖子:深入理解JavaScript系(2):Module希望上面的一些例子,能讓你對立即調(diào)用的函數(shù)表達(dá)(也就是我們所說的自執(zhí)行函數(shù))有所了解,如果你想了解關(guān)于unton和odue模式的信息,請繼續(xù)訪問下面列出的:ECMA-262-3indetail.Chapter5.Functions.-DmitryA.Functionsandfunctionscope-MozillaDeveloperNamedfunctionexpressions-Juriy“kangax”ModuleBenCherry(大叔翻譯整理ClosuresexinedwithJavaScript-Nick強(qiáng)大的原型和原型JavaScriptprototypalJavaScriptJavaScriptJavaScript10年前,我剛學(xué)習(xí)JavaScriptvarvardecimalDigits=2,tax=5;functionadd(x,y){returnx+y;}functionsubtract(x,y){returnx-y;}//alert(add(1,通過執(zhí)行各個function美varvarCalculator=function(decimalDigits,tax){this.decimalDigits=decimalDigits;this.tax=然后,通過給Calculator對象的prototype對象字面量來設(shè)定CtotypeCtotype={add:function(x,y){returnx+y;subtract:function(x,y){returnx-y;}//alert((newCalculator()).add(1,這樣,我們就可以newCalculator對象以后,就可以調(diào)用add第二種方式是,在賦值原型prototype的時候使用functionCtotypeCtotype=function(){}它的好處面的帖子里已經(jīng)知道了,就是可以封裝私有的function,通過的形式出簡單的使用名稱,以達(dá)到public/private的效果,修改后的代碼如下CtotypeCtotype=function(){add=function(x,y){returnx+subtract=function(x,y){returnx-y;}returnadd:add,subtract:subtract}}//alert((newCalculator()).add(11,同樣的方式,我們可以newCalculator對象以后調(diào)用add分步varvarBaseCalculator=function() 一個小數(shù)位this.decimalDigits=BaseCalculator2BaseCtotype.add=function(x,y){returnx+y;BaseCtotype.subtract=function(x,y){returnx-y;首先,了一個BaseCalculator對象,構(gòu)造函數(shù)里會初始化一個小數(shù)位數(shù)的屬性decimalDigits,然后通過原型屬性設(shè)置2個function,分別是add(x,y)和subtract(x,y2是看如何將BaseCalculator對象設(shè)置到真正的Calculator的原型上。varvarBaseCalculator=function(){this.decimalDigits=2;BaseCtotype={add:function(x,y){returnx+subtract:function(x,y){returnx-y;}}varvarCalculator=function()this.tax=Ctotype=new我們可以看到Calculator的原型是指向到BaseCalculatorCalculator集成它的add(x,y)和subtract(x,y2個function,還有一點要說的是,由于它的原型是BaseCalculator的一個實例,所以不管你創(chuàng)建多少個Calculator對象實例,他們的原型指向的都是同一個實例。varvarcalc=newalert(calc.add(1,//BaseCalculator的decimalDigitsCalculator上面的代碼,運(yùn)行以后,我們可以看到因為Calculator的原型是指向

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論