溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

js函數(shù)回調(diào)的示例

發(fā)布時間:2020-11-10 14:15:36 來源:億速云 閱讀:116 作者:小新 欄目:web開發(fā)

小編給大家分享一下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è)資訊頻道!

向AI問一下細節(jié)

免責聲明:本站發(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)容。

AI