搜尋
首頁web前端js教程js函數的回調

js函數的回調

Aug 06, 2019 pm 04:35 PM
js

平常的前端開發工作中,寫js時會有很多地方用到函數的回呼。

最簡單的例子就是:

<script>
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><p>自從有了Apply,事情就變得如此簡單</p>
<p>Array.prototype.push.apply(arr1,arr2)</p>
<p>一行程式碼就解決了,原理能看的出來,Array.prototype.push是指數組的push函數,apply(arr1,arr2)說明arr1是作用域,就等同於是arr1調用了數組的push函數,</p> <p>而且arr1的確就是個數組,所以可以調用,arr2表示入參的數組。所以,以上語句等同於:arr1.push(3,4,5)。 (<strong>push函數支援傳遞多個入參,這也是這裡可以使用apply的前提條件)</strong></p>
<p>#以上語句也可以寫成:arr1.push.apply(arr1,arr2); 兩者完全等效,因為arr1.push表示arr1的push函數,也就是陣列的push函數。 </p>
<p>如果使用call就是這樣Array.prototype.push.call(arr1,arr2[0],arr2[1]...),顯然還是apply適合。 </p>
<p>要是你還問,那直接用arr1.push(3,4,5)不就行了,那已經暴露了你的智商,arr2又不是不可以變,下次不是[3,4 ,5]了呢。 </p>
<p>還有取得陣列中,最大的數字,也可以用apply呼叫Math.max函數</p>
<p>var arr1=[1,3,4];</p>
<p>alert (Math.max.apply(window,arr1)); /* 作用域可以不是window,就算是null都行,Math.max.apply(this,arr1),Math.max.apply(null,arr1) */ </p>
<p>4、工作中函數回呼的實際例子</p>
<p>有了上面的基礎,就能看的懂工作中封裝好的js的回呼函數了</p>
<p>背景:頁面A需要使用頁面B來選擇某個項目,然後帶回這個項目的資訊給頁面A,頁面A根據這些資訊豐富自己。 </p>
<p>頁面A:</p>
<pre class="brush:php;toolbar:false">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>返回时执行的方法,一般为重新绑定
 
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函數的回調的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:CSDN。如有侵權,請聯絡admin@php.cn刪除
超越瀏覽器:現實世界中的JavaScript超越瀏覽器:現實世界中的JavaScriptApr 12, 2025 am 12:06 AM

JavaScript在現實世界中的應用包括服務器端編程、移動應用開發和物聯網控制:1.通過Node.js實現服務器端編程,適用於高並發請求處理。 2.通過ReactNative進行移動應用開發,支持跨平台部署。 3.通過Johnny-Five庫用於物聯網設備控制,適用於硬件交互。

使用Next.js(後端集成)構建多租戶SaaS應用程序使用Next.js(後端集成)構建多租戶SaaS應用程序Apr 11, 2025 am 08:23 AM

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務

如何使用Next.js(前端集成)構建多租戶SaaS應用程序如何使用Next.js(前端集成)構建多租戶SaaS應用程序Apr 11, 2025 am 08:22 AM

本文展示了與許可證確保的後端的前端集成,並使用Next.js構建功能性Edtech SaaS應用程序。 前端獲取用戶權限以控制UI的可見性並確保API要求遵守角色庫

JavaScript:探索網絡語言的多功能性JavaScript:探索網絡語言的多功能性Apr 11, 2025 am 12:01 AM

JavaScript是現代Web開發的核心語言,因其多樣性和靈活性而廣泛應用。 1)前端開發:通過DOM操作和現代框架(如React、Vue.js、Angular)構建動態網頁和單頁面應用。 2)服務器端開發:Node.js利用非阻塞I/O模型處理高並發和實時應用。 3)移動和桌面應用開發:通過ReactNative和Electron實現跨平台開發,提高開發效率。

JavaScript的演變:當前的趨勢和未來前景JavaScript的演變:當前的趨勢和未來前景Apr 10, 2025 am 09:33 AM

JavaScript的最新趨勢包括TypeScript的崛起、現代框架和庫的流行以及WebAssembly的應用。未來前景涵蓋更強大的類型系統、服務器端JavaScript的發展、人工智能和機器學習的擴展以及物聯網和邊緣計算的潛力。

神秘的JavaScript:它的作用以及為什麼重要神秘的JavaScript:它的作用以及為什麼重要Apr 09, 2025 am 12:07 AM

JavaScript是現代Web開發的基石,它的主要功能包括事件驅動編程、動態內容生成和異步編程。 1)事件驅動編程允許網頁根據用戶操作動態變化。 2)動態內容生成使得頁面內容可以根據條件調整。 3)異步編程確保用戶界面不被阻塞。 JavaScript廣泛應用於網頁交互、單頁面應用和服務器端開發,極大地提升了用戶體驗和跨平台開發的靈活性。

Python還是JavaScript更好?Python還是JavaScript更好?Apr 06, 2025 am 12:14 AM

Python更适合数据科学和机器学习,JavaScript更适合前端和全栈开发。1.Python以简洁语法和丰富库生态著称,适用于数据分析和Web开发。2.JavaScript是前端开发核心,Node.js支持服务器端编程,适用于全栈开发。

如何安裝JavaScript?如何安裝JavaScript?Apr 05, 2025 am 12:16 AM

JavaScript不需要安裝,因為它已內置於現代瀏覽器中。你只需文本編輯器和瀏覽器即可開始使用。 1)在瀏覽器環境中,通過標籤嵌入HTML文件中運行。 2)在Node.js環境中,下載並安裝Node.js後,通過命令行運行JavaScript文件。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
4 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器