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