您好,登錄后才能下訂單哦!
小編給大家分享一下js函數(shù)回調(diào)的示例,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
平常的前端開發(fā)工作中,編寫js時會有很多地方用到函數(shù)的回調(diào)。
最簡單的例子就是:
<script language="javascript" type="text/javascript"> function doSomething(callback) { if(typeof callback == "function") { callback(); } } function foo() { alert("我是回調(diào)后執(zhí)行的函數(shù)"); } doSomething(foo); /*正確*/ doSomething(function(){ alert("我是回調(diào)后執(zhí)行的函數(shù)"); }); /*正確*/ doSomething("foo"); /* 這樣是不行的,傳入的是一個字符串,不是一個函數(shù)名 */ </script>
以上只能回調(diào)沒有參數(shù)的(除法你事先知道回調(diào)的函數(shù)的參數(shù)),如果函數(shù)有未知的函數(shù),就不能如此簡單的調(diào)用了。
高級方法:
1、使用javascript的call方法
function doSomething(callback,arg1,arg2) { callback.call(this,arg1,arg2); } function foo(arg1,arg2) { alert(arg1+":"+arg2); } doSomething(foo,1,2); /* 彈出了1:2 */
2、使用javascript 的 apply方法
function doSomething(callback,args) { callback.apply(window,args); } function foo(arg1,arg2) { alert(arg1+":"+arg2); } doSomething(foo,[1,2,3]); /* 彈出了1:2 */
可以看成call和apply基本一樣,區(qū)別就是call只能一個個傳參數(shù),apply只能把參數(shù)放數(shù)組里傳進來。
他們的第一個參數(shù)都是作用域,比如上面?zhèn)髁藅his,表示就是和doSomething這個函數(shù)一樣的作用域,當然你也可以傳window,表示整個window的作用域。
3、apply的巧妙用法
apply也可以看作是函數(shù)的執(zhí)行函數(shù),就是用來執(zhí)行某個函數(shù)的函數(shù)。所以你會發(fā)現(xiàn),有時候用好apply,有很多原本繁雜的事情會變得如此簡單。
比如數(shù)組的push方法使用apply來調(diào)用:
var arr1=[1,3,4];
var arr2=[3,4,5];
如果我們要把 arr2展開,然后一個一個追加到arr1中去,最后讓arr1=[1,3,4,3,4,5]
arr1.push(arr2)顯然是不行的。 因為這樣做會得到[1,3,4,[3,4,5]]
我們只能用一個循環(huán)去一個一個的push(當然也可以用arr1.concat(arr2),但是concat方法并不改變arr1本身)
var arrLen=arr2.length for(var i=0;i<arrLen;i++){ arr1.push(arr2[i]); }
自從有了Apply,事情就變得如此簡單
Array.prototype.push.apply(arr1,arr2)
一行代碼就解決了,原理能看的出來,Array.prototype.push是指數(shù)組的push函數(shù),apply(arr1,arr2)說明arr1是作用域,就等同于是arr1調(diào)用了數(shù)組的push函數(shù),
而且arr1的確就是個數(shù)組,所以可以調(diào)用,arr2表示入?yún)⒌臄?shù)組。所以,以上語句等同于:arr1.push(3,4,5)。(push函數(shù)支持傳遞多個入?yún)?,這也是這里可以使用apply的前提條件)
以上語句也可以寫成:arr1.push.apply(arr1,arr2); 兩者完全等效,因為arr1.push表示arr1的push函數(shù),也就是數(shù)組的push函數(shù)。
如果使用call就是這樣Array.prototype.push.call(arr1,arr2[0],arr2[1]...),顯然還是apply合適。
要是你還問,那直接用arr1.push(3,4,5)不就行了,那已經(jīng)暴露了你的智商,arr2又不是不可以變,下次不是[3,4,5]了呢。
還有獲取數(shù)組中,最大的那個數(shù)字,也可以使用apply調(diào)用Math.max函數(shù)
var arr1=[1,3,4];
alert(Math.max.apply(window,arr1)); /* 作用域可以不是window,就算是null都行,Math.max.apply(this,arr1),Math.max.apply(null,arr1) */
4、工作中函數(shù)回調(diào)的實際例子
有了上面的基礎(chǔ),就能看的懂工作中封裝好的js的回調(diào)函數(shù)了
背景:頁面A需要使用頁面B來選擇某個項目,然后帶回這個項目的信息給頁面A,頁面A根據(jù)這些信息豐富自己。
頁面A:
noticeInfo = { selectProject: function () { var win = newsee.ui.window win.show('項目列表', '../Project/ProjectSelectList.html?callback=noticeInfo.setProjectInfo', { size: win.winSizeType.big }) //在當前頁面彈出框,框里面是另一個頁面,地址后面帶上需要回調(diào)的函數(shù)名 //注意這兩個頁面其實都是在一個頁面里面的,并不是像window.open()那樣出現(xiàn)了新窗口,所以兩個頁面的js都是可見的 }, setProjectInfo: function (obj) { //回調(diào)函數(shù),將選擇好的項目對象傳進來,然后豐富自己的頁面 $('#projectName').val(obj.name) $('#projectID').val(obj.id) } }
頁面B:
function SelectBack() { var callback = newsee.util.url.getQuery('callback'); //獲取頁面參數(shù)callback,這里獲取到的是"noticeInfo.setProjectInfo",是個字符串 var arr = newsee.ui.grid.getSelectedBack('datagrid') //獲取選擇的項目,這個不用深究 if (!arr.length) { return newsee.ui.window.alert('請選擇項目!') } newsee.util.url.back(callback, arr[0]) //重點來了,這里執(zhí)行回調(diào),將需要回調(diào)的函數(shù)名和入?yún)鬟M來,arr[0]就是選擇的項目的對象的數(shù)組了(它也是個數(shù)組,里面就一個對象) }
newsee.util.url.back函數(shù)如下:
back : function (funcName) { // / <param name="funcName" type="String">返回時執(zhí)行的方法,一般為重新綁定</param> var isWindow = typeof $$winClose === 'function',// 是否為彈窗 args // 彈窗返回方法參數(shù) if (isWindow) {// 彈窗的返回方法 $$winClose() args = [].slice.call(arguments) //arguments大家應(yīng)該都知道的吧,它可以用來獲取函數(shù)的實參,它類似數(shù)組又不是數(shù)組,這句代碼就是把它轉(zhuǎn)換成數(shù)組,因為apply的入?yún)⑿枰莻€數(shù)組才行 //args現(xiàn)在里面有兩個元素,args[0]=callback,就是之前傳進來的回調(diào)函數(shù)名,args[1]=arr[0],就是回調(diào)函數(shù)的入?yún)? newsee.callFunc.apply(newsee, args) //執(zhí)行 newsee.callFunc 函數(shù),作用域就是newsee自己(等同于newsee自己調(diào)用callFunc函數(shù)),參數(shù)是args } }
newsee.callFunc函數(shù)如下:
callFunc: function(funcName, arg) { var func = typeof funcName === 'function' ? funcName : this.findItem(window, funcName) //上面我有提到過,doSomething("foo"); 傳入的是一個字符串,不是一個函數(shù)名,所以無法執(zhí)行 //同樣的道理,現(xiàn)在funcName=args[0]=callback="noticeInfo.setProjectInfo",是個字符串,不能直接調(diào)用apply,需要變成函數(shù) //這句話就是用來判斷funcName是不是一個函數(shù),如果不是,就在window作用域里根據(jù)funcName找到這個函數(shù),然后賦給func if (typeof func === 'function') { //此時func已經(jīng)是個函數(shù)了,就是頁面A里定義的noticeInfo.setProjectInfo() try { return func.apply(window, arg) //執(zhí)行需回調(diào)的函數(shù),作用域依然是window,反正這個函數(shù)在window里肯定能找到,參數(shù)就是arg=args[1]=arr[0],即之前在頁面B獲取到的項目對象 } catch (e) { console.error(e) } } }
ok,需回調(diào)的函數(shù)就這樣被執(zhí)行了,至于怎么根據(jù)字符串形式的函數(shù)名獲取這個函數(shù),看下面。
//findItem函數(shù)如下: findItem: function(data, key) { // / <summary>獲取對象指定鍵的值</summary> if (this.include(data, key)) { //data這里就是傳進來的window,注意window就是一個對象,首先判斷window對象里是否存在"noticeInfo.setProjectInfo"這個屬性 return eval('data.' + key) //如果存在,就執(zhí)行"data.noticeInfo.setProjectInfo",這樣就獲取到了這個函數(shù)了。(eval() 函數(shù)可計算某個字符串,并執(zhí)行其中的的 JavaScript 代碼) } } //include函數(shù)如下: include: function(data, key) { // / <summary>判斷對象是否存在鍵值</summary> if (data == null || typeof data !== 'object' || !key || typeof key !== 'string') { return false } var keys = key.split('.'), item = data, result = true keys.forEach(function(k) { if (item != null && typeof item === 'object' && k in item) { //依次循環(huán)遍歷,第一次item = data,那就是window這個對象,k="noticeInfo",window[noticeInfo]是存在的,因為在頁面A里定義了noticeInfo這么一個對象 //第二次循環(huán),item=window.noticeInfo,k="setProjectInfo",window.noticeInfo[setProjectInfo]也是存在的,因為在頁面A里也定義了setProjectInfo這么一個函數(shù) //這里沒有第三次循環(huán)了,所以最后返回是true,說明window對象里存在"noticeInfo.setProjectInfo"這個屬性,接下來使用eval()拿到它即可 item = item[k] } else { return result = false } }) return result }
對eval() 函數(shù)也介紹一下:
eval() 函數(shù)可計算某個字符串,并執(zhí)行其中的的 JavaScript 代碼。
返回值就是通過計算 string 得到的值(如果有的話)。如:
eval("x=10;y=20;document.write(x*y)") //輸出 200 document.write(eval("2+2")) //輸出 4 var x=10 document.write(eval(x+17)) //輸出 27
所以上面的eval('data.' + key)就是執(zhí)行"data.noticeInfo.setProjectInfo"這個字符串,
因為data在這里就是指window,所以返回值就是window.noticeInfo.setProjectInfo()這個函數(shù)
其實可以在簡單一點,根本沒必要使用eval()來獲取這個函數(shù),因為在include函數(shù)里,item就已經(jīng)是window.noticeInfo.setProjectInfo這個對象了,這個對象就是我們想要的函數(shù)。
(在js中函數(shù)也是對象,函數(shù)名就是這個函數(shù)的引用,就和地址差不多)
既然都拿到這個函數(shù)了,直接返回不就行了,所以上面的include()和findItem可以這樣簡化:
include: function(data, key) { if (data == null || typeof data !== 'object' || !key || typeof key !== 'string') { }else{ var keys = key.split('.'), item = data, result = true keys.forEach(function(k) { if (item != null && typeof item === 'object' && k in item) { item = item[k] } else { result = false; } }) if(result) return item } }, findItem: function(data, key) { return this.include(data, key)
經(jīng)過測試,發(fā)現(xiàn)這兩個根據(jù)字符串形式的函數(shù)名獲取函數(shù)的方法都可以達到一模一樣的效果。
以上是js函數(shù)回調(diào)的示例的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。