標籤:
函數的範圍和this的指向我已經在前面的文章中講過,今天主要講講函數的綁定。函數綁定要建立一個函數,可以在特定的this環境中以指定參數調用另外一個函數。該技巧常常和回呼函數與事件處理常式一起使用,以便在將函數作為變數傳遞的同時保留函數的代碼執行環境。
函數綁定
看下面的例子:
var handler = { message:"訊息來了!", handlerClick :function(event){ document.write(this.message); }}//一般的指定不能改變this的指向var btn = document.getElementById("btn");btn.addEventListener("click",handler.handlerClick,false);//返回undefined 因為this的範圍指向的是btn而不是hanlder
結果返回的是undefined,因為this的指向是btn這個DOM對象而不是hanlder,所以根本找不到handler.message。
所幸的是,我們可以通過一個閉包來解決這個問題。
//可以通過一個閉包來解決這個問題btn.addEventListener("click",function(event){ handler.handlerClick(event);},false);//返回 訊息來了!,解決問題
但是用閉包始終不是一個好辦法,因為過多的閉包會使代碼變得不易調試和理解,所以我們可以利用apply來調整this的指向。接下來我們定義一個bind方法。
//但是過多的使用閉包並不是一個好辦法,所以我們使用apply來改變this的指向function bind(fn,context){ return function(){ return fn.apply(context,arguments); };}//通過自訂的bind方法來綁定事件btn.addEventListener("click",bind(handler.handlerClick,handler),false);
這樣就可以成功的將this的指向改變,這也是很多javascript第三方庫綁定函數的方法。值得一提的是,ES5中內建就有bind方法,這樣就不用我們再去自訂一個bind了:
//ES5中內建就有bind方法,就不需要我們自訂bind方法了。//使用內建的bind方法btn.addEventListener("click",handler.handlerClick.bind(handler),false);
函數柯裡化
什麼叫做函數柯裡化呢?其實就是function currying的翻譯。curry是咖喱的意思,呵呵。好了,迴歸正題,currying可以理解為就是用於建立已經設定好了一個或多個參數的函數。實現方法和函數綁定一樣,都是通過閉包來返回一個函數。兩者的區別在於,當函數被調用時,返回的函數還需要設定一些傳入的參數。
//再來說說函數柯裡化//概念:用於建立已經設定好了一個或多個參數的函數,可以理解為函數中套函數function add(num1,num2){ return num1+num2;}function curriedAdd(num3){ return add(5,num3);}document.write(add(2,3)+"<br>");//5document.write(curriedAdd(3));//8//上面的例子可以展示柯裡化的概念
上面的例子雖然不是柯裡化函數,但是可以展示其概念。下面我們介紹下建立函數柯裡化的通用方法:
//下面介紹建立函數柯裡化的通用方法function curry(fn){ var args = Array.prototype.slice.call(arguments,1); return function(){ var innerArgs = Array.prototype.slice.call(arguments); var finalArgs = args.concat(innerArgs);//將innerArgs拼接到args後 return fn.apply(null,finalArgs); }}//使用方法如下:var curriedAdd = curry(add,5);document.write(curriedAdd(3)+"<br>");//8var curriedAddB = curry(add,5,10);document.write(curriedAddB()+"<br>");//15//可以看到參數靈活多變
也許看到這裡,還不能夠理解到底有什麼作用,那麼,我們可以將其和函數綁定結合起來,實現隨意數量的傳遞參數:
//這樣就可以在處理事件程式時傳遞其他參數了。//比如下例子:,注意我們傳入了name參數var handlerB = { message:‘訊息來了!‘, handlerClick : function(name,event){ document.write(this.message+":"+name); }}btn.addEventListener("click",curriedBind(handlerB.handlerClick,handler,‘liufang‘),false);//訊息來了!:liufang
ES5中內建的bind方法同樣已實現了柯裡化,使用方法如下:
//ES5中的bind已經實現了柯裡化,所以可以直接使用:btn.addEventListener("click",handlerB.handlerClick.bind(handlerB,"liufangagain"),false);//訊息來了!:liufangagain
函數綁定和函數柯裡化提供了強大的動態函數功能,它們可以用於建立複雜的演算法和功能,但是會帶來額外的開銷。
本文全部執行個體地址: demo
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
深入理解javascript之函數