函數是第一類對象 first-class object,能夠做爲帶有屬性和方法的值以及參數進行傳遞。 node
建立函數的語法 瀏覽器
function foo(){}; //函數聲明 var bar=function(){}; //函數表達式 var baz=function baz(){};//函數命名錶達式
//反模式 //僅用於掩飾 //全局函數 function foo(){ alert("global foo"); } function bar(){ alert("global bar"); } function hoisMe(){ console.log(typeof foo); //輸出function console.log(typeof bar); //輸出undefined foo(); //輸出local foo bar(); //輸出 TypeError: bar is not a function //函數聲明 //變量 foo以其實現者被提高 function foo(){ alert("local foo"); } //函數表達式 //僅變量 bar被提高 //函數實現並未被提高 var bar=function(){ alert("local bar"); } } hoisMe();
//重構findNodes()以接受一個回調函數 var findNodes=function(callback){ var i=100000, nodes=[], found; if(typeof callback!=="function"){ callback=false; } while(i){ i-=1; // 這裏是複雜的邏輯... //如今進行回調函數 if(callback){ callback(found); } nodes.push(found); } return nodes; } //回調函數 var hide=function(node){ node.style.display="none"; } //找到制定節點,並在後續執行中將其隱藏起來 findNodes(hide);
//傳遞一個匿名回調函數 findNodes(function(node){ node.style.display="block"; });
//重構findNodes()以接受一個回調函數 var findNodes=function(callback,callback_obj){ var i=100000, nodes=[], found; while(i){ i-=1; // 這裏是複雜的邏輯... //如今進行回調函數 if(typeof callback==="string"){ callback=callback_obj[callback]; } if(typeof callback==="function"){ callback.call(callback_obj,found); } nodes.push(found); } return nodes; } //回調函數 var myapp={}; myapp.color="green"; myapp.paint=function(node){ node.style.color=this.color; }; //找到制定節點,並在後續執行中將其隱藏起來 findNodes(myapp.paint,myapp);
var setup=function(){ alert(1); return function(){ alert(2); } } //使用setup函數 var my=setup(); //alert1 my(); //alert 2
var setup=function(){ var count=0; return function(){ return (count+=1); } } //用法 var next=setup(); next(); //返回1 next(); //返回2 next(); //返回3
惰性函數定義 lazy function definition 緩存
var scareMe=function(){ alert("Boo!"); scareMe=function(){ alert("Double boo!"); } }; //使用自定義函數 scareMe(); //輸出Boo! scareMe(); //輸出Double boo!
var scareMe=function(){ alert("Boo!"); scareMe=function(){ alert("Double boo!"); } }; //1 .添加一個新的屬性 scareMe.property="properly"; //2. 複製給另外一個不一樣名稱的變量 var prank=scareMe; //3. 做爲一個方法使用 var spooky={ boo:scareMe }; //calling with a new name prank(); //輸出 Boo! prank(); //輸出 Boo! console.log(prank.property); //輸出properly //做爲一個方法來調用 spooky.boo(); //輸出Boo! spooky.boo(); //輸出Boo! console.log(spooky.boo.property); // 輸出 properly //使用自定義函數 scareMe(); //輸出 Double boo! scareMe(); //輸出 Double boo! console.log(scareMe.property); //undefined
即時函數也叫自調用self-invoking 或者自執行self-executing函數。 閉包
即時函數中定義的變量將會用於它自身的局部變量,沒必要擔憂全局空間被臨時的變量污染。 app
//定義模塊module1 (function(){ //模塊1中的全部代碼 }());
本例子中即時函數的返回值是一個函數,它將分配給變量getResult,而且將簡單地返回res值,該值被預計算並存儲在即時函數的閉包中 ide
var getResult=(function(){ var res=2+2; return function(){ return res; } }());
定義對象屬性時也可使用即時函數 函數
var o={ message:(function(){ var who="me", what="call"; return what + " "+who; }()), getMsg:function(){ return this.message; } }; //用法 console.log(o.getMsg()); //輸出call me console.log(o.message); //輸出call me
immediate object initalization 測試
({ //在這裏能夠定義設定值 //又名配置常數 maxwidth:600, maxheight:400, //還能夠定義一些實用的方法 gimmeMax:function(){ return this.maxwidth+ "X" +this.maxheight; }, //初始化 init:function(){ console.log(this.gimmeMax()); //更多初始化任務。。。 } }).init();
init-time branching 也稱爲加載時分支 load-time branching 是一種優化模式 優化
//接口 var utils={ addListener:null, removeListener:null }; //實現 if(typeof window.addEventListener==="function"){ utils.addListener=function(el,type,fn){ el.addEventListener(type,fn,false); }; utils.removeListener=function(el,type,fn){ el.removeEventListener(type,fn,false); } }else if(typeof document.attachEvent==="function"){ //判斷爲IE瀏覽器 utils.addListener=function(el,type,fn){ el.attachEvent('on'+type,fn); }; utils.removeListener=function(el,type,fn){ el.detachEvent("on"+type,fn); }; }else{ //更早版本的瀏覽器 utils.addListener=function(el,type,fn){ el['on'+type]=fn; }; utils.removeListener=function(el,type,fn){ el['on'+type]=null; } }
對於每一個函數,它都會自動得到一個length屬性,其中包含了該函數指望的參數數量。 this
function func(a,b,c,d){} console.log(func.length);
能夠在任什麼時候候將自定義屬性添加到你的函數中。自定義屬性的其中一個用例是緩存函數結果(即返回值),所以下次調用該函數時就不會重作潛在的繁重計算。 緩存函數結果也被稱爲備忘memoization
var myFunc=function(param){ if(!myFunc.cache[param]){ var result={}; //。。。開銷很大的操做。。。 myFunc.cache[param]=result; } return myFunc.cache[param]; } //緩存存儲 myFunc.cache={};
當須要傳遞大量參數時,一個更好的辦法是僅使用一個參數對象來代替全部參數,該參數對象稱爲conf,也就是配置的意思。
var conf={ username:"lilu", first:"Yi", last:"Liu" } function addPerson(person){ return person.username +" " +person.first+" "+person.last; } addPerson(conf);
調用invoking函數和應用applying函數能夠獲得相同的結果
//定義函數 var sayHi=function(who){ return "Hello"+ (who?", "+who:"")+"!"; }; //調用函數 sayHi(); //輸出Hello sayHi('world'); //輸出Hello,World! //應用函數 sayHi.apply(null,['hello']); //輸出Hello, hello!
//curry化的add()函數 //接受部分參數的列表 function add(x,y){ var oldx=x,oldy=y; if(typeof oldy==="undefined"){ //部分 return function(newy){ return oldx+newy; } } //徹底應用 return x+y; } //測試 typeof add(5); //輸出function add(3)(4); //7 //建立病存儲一個新函數 var add2000=add(2000); add2000(10);//輸出2010
一個通用curry化函數
function schonfinkelize(fn){ var slice=Array.prototype.slice, stored_args=slice.call(arguments,1); return function(){ var new_args=slice.call(arguments), args=stored_args.concat(new_args); return fn.apply(null,args); } } //普通函數 function add(x,y){ return x+y; } //將一個函數curry化以得到一個新的函數 var newadd=schonfinkelize(add,5); newadd(4); //輸出9 /另外一種選擇——直接調用新函數 schonfinkelize(add,6)(7);
更多用法
//普通函數 function add(a,b,c,d,e){ return a+b+c+d+e; } //可運行於任意數量的參數 schonfinkelize(add,1,2,3)(5,5); //16 //兩步curry化 var addOne=schonfinkelize(add,1); addOne(10,10,10,10); //輸出41 var addSix=schonfinkelize(addOne,2,3); addSix(5,5); //輸出16