Maison >interface Web >js tutoriel >rappel de fonction js
Dans le travail normal de développement front-end, les rappels de fonctions sont utilisés à de nombreux endroits lors de l'écriture de js.
L'exemple le plus simple est :
<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>
Ce qui précède ne peut que rappeler sans paramètres (sauf si vous connaissez les paramètres de la fonction de rappel à l'avance. Si la fonction a des fonctions inconnues, cela ne peut pas être le cas). simple.
Méthodes avancées :
1. Utilisez la méthode d'appel de javascript
function doSomething(callback,arg1,arg2) { callback.call(this,arg1,arg2); } function foo(arg1,arg2) { alert(arg1+":"+arg2); } doSomething(foo,1,2); /* 弹出了1:2 */
2 Utilisez la méthode d'application de javascript
function doSomething(callback,args) { callback.apply(window,args); } function foo(arg1,arg2) { alert(arg1+":"+arg2); } doSomething(foo,[1,2,3]); /* 弹出了1:2 */
peut être. considéré comme un appel C'est fondamentalement la même chose qu'apply. La différence est que call ne peut transmettre que les paramètres un par un, et apply ne peut transmettre que les paramètres d'un tableau.
Leurs premiers paramètres sont tous des portées. Par exemple, si ceci est passé ci-dessus, cela signifie qu'il a la même portée que la fonction doSomething. Bien sûr, vous pouvez également passer window, ce qui signifie la portée entière de la fenêtre.
3. L'utilisation intelligente de apply
apply peut également être considérée comme la fonction d'exécution d'une fonction, qui est une fonction utilisée pour exécuter une certaine fonction. Ainsi, vous constaterez que parfois, si vous utilisez correctement apply, de nombreuses choses qui étaient initialement compliquées deviendront si simples.
Par exemple, la méthode push d'un tableau est appelée en utilisant apply :
var arr1=[1,3,4];
var arr2=[3,4 ,5];
Si nous voulons développer arr2, puis ajouter à arr1 un par un, enfin laissez arr1=[1,3,4,3,4,5]
arr1 .push(arr2 ) n’est évidemment pas possible. Parce que faire cela obtiendra [1,3,4,[3,4,5]]
Nous ne pouvons utiliser une boucle que pour pousser un par un (bien sûr, vous pouvez également utiliser arr1.concat(arr2) , mais la méthode concat ne change pas arr1 elle-même)
var arrLen=arr2.length for(var i=0;i<arrLen;i++){ arr1.push(arr2[i]); }
Depuis qu'il existe Apply, les choses sont devenues si simples
Array.prototype.push.apply(arr1, arr2)
Une ligne de code résout le problème. Le principe est clairement visible. Array.prototype.push est la fonction push du tableau apply(arr1, arr2) qui indique que arr1 est la portée, ce qui équivaut à arr1 appelant le. fonction push du tableau.
Et arr1 est bien un tableau, donc il peut être appelé, et arr2 représente le tableau de paramètres. Par conséquent, l’instruction ci-dessus équivaut à : arr1.push(3,4,5). (La fonction push prend en charge la transmission de plusieurs paramètres d'entrée, ce qui est également une condition préalable à l'utilisation de apply ici)
L'instruction ci-dessus peut également être écrite sous la forme : arr1.push.apply(arr1, arr2 ); Les deux Les deux sont complètement équivalents, car arr1.push représente la fonction push de arr1, qui est la fonction push du tableau.
Si vous utilisez call, c'est comme Array.prototype.push.call(arr1, arr2[0], arr2[1]...), il est évidemment toujours approprié de postuler.
Si vous demandez toujours, pourquoi n'utilisez-vous pas simplement arr1.push(3,4,5) ? Ce n'est pas comme si arr2 ne pouvait pas être modifié la prochaine fois. [3,4,5].
Pour obtenir le plus grand nombre du tableau, vous pouvez également utiliser apply pour appeler la fonction Math.max
var arr1=[1,3,4];
alert (Math.max.apply(window,arr1)); /* La portée n'a pas besoin d'être une fenêtre, même si elle est nulle, Math.max.apply(this,arr1), Math.max.apply(null, arr1) */
4. Exemples pratiques de rappels de fonctions au travail
Avec la base ci-dessus, vous pouvez comprendre les fonctions de rappel de js emballées dans work
Contexte : Page A doit utiliser la page B pour sélectionner un élément, puis ramène les informations sur cet élément à la page A. La page A s'enrichit en fonction de ces informations.
Page 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) } }
Page 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]就是选择的项目的对象的数组了(它也是个数组,里面就一个对象) }
la fonction newsee.util.url.back est la suivante :
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 } }
la fonction newsee.callFunc est comme suit :
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, la fonction qui doit être rappelée est exécutée. Quant à savoir comment obtenir cette fonction en fonction du nom de la fonction sous forme de chaîne, voir ci-dessous.
//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 }
Introduisez également la fonction eval() :
La fonction eval() peut calculer une certaine chaîne et y exécuter le code JavaScript.
La valeur de retour est la valeur obtenue en calculant la chaîne (le cas échéant). Par exemple :
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
Donc, l'eval('data.' + key) ci-dessus consiste à exécuter la chaîne "data.noticeInfo.setProjectInfo",
Parce que les données ici font référence à la fenêtre, donc renvoie La valeur est la fonction window.noticeInfo.setProjectInfo()
En fait, cela peut être plus simple Il n'est pas nécessaire d'utiliser eval() pour obtenir cette fonction, car dans la fonction include, l'élément est. déjà window.noticeInfo.setProjectInfo Cet objet est la fonction que nous voulons.
(En js, les fonctions sont aussi des objets. Le nom de la fonction est une référence à cette fonction, qui est presque la même que l'adresse)
Puisque nous avons cette fonction, nous ne pouvons pas la renvoyer directement. C'est tout, donc les include() et findItem ci-dessus peuvent être simplifiés comme ceci :
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)
Après les tests, il a été constaté que ces deux méthodes d'obtention de fonctions basées sur les noms de fonctions sous forme de chaîne peuvent produire exactement le même effet.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!