Home >Web Front-end >JS Tutorial >js function callback
In normal front-end development work, function callbacks are used in many places when writing js.
The simplest example is:
<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>
The above can only callback without parameters (division you know the parameters of the callback function in advance). If the function has an unknown function, it cannot be so simple. Called.
Advanced method:
1. Use the call method of 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. Use the apply method of javascript
function doSomething(callback,args) { callback.apply(window,args); } function foo(arg1,arg2) { alert(arg1+":"+arg2); } doSomething(foo,[1,2,3]); /* 弹出了1:2 */
can be regarded as call It is basically the same as apply. The difference is that call can only pass parameters one by one, and apply can only pass parameters in an array.
Their first parameters are all scopes. For example, if this is passed above, it means that it has the same scope as the doSomething function. Of course, you can also pass window, which means the entire window. scope.
3. Clever usage of apply
apply can also be regarded as the execution function of a function, which is a function used to execute a certain function. So you will find that sometimes if you use apply well, many things that were originally complicated will become so simple.
For example, the push method of an array is called using apply:
var arr1=[1,3,4];
var arr2=[3,4,5];
If we want to expand arr2, then append to arr1 one by one, and finally let arr1=[1,3,4,3,4,5]
arr1.push(arr2 ) is obviously not possible. Because doing this will get [1,3,4,[3,4,5]]
We can only use a loop to push one by one (of course you can also use arr1.concat(arr2), but The concat method does not change arr1 itself)
var arrLen=arr2.length for(var i=0;i<arrLen;i++){ arr1.push(arr2[i]); }
Since there is Apply, things have become so simple
Array.prototype.push.apply(arr1, arr2)
One line of code solves the problem. The principle can be seen. Array.prototype.push is the push function of the array. apply(arr1, arr2) indicates that arr1 is the scope, which is equivalent to arr1 calling the push function of the array.
And arr1 is indeed an array, so it can be called, and arr2 represents the array of parameters. Therefore, the above statement is equivalent to: arr1.push(3,4,5). (The push function supports passing multiple input parameters, which is also a prerequisite for apply to be used here)
The above statement can also be written as: arr1.push.apply(arr1, arr2); Both The two are completely equivalent, because arr1.push represents the push function of arr1, which is the push function of the array.
If you use call, it is like Array.prototype.push.call(arr1, arr2[0], arr2[1]...), obviously apply is still appropriate.
If you still ask, why not just use arr1.push(3,4,5)? That has exposed your IQ. It is not that arr2 cannot be changed. Next time it will not be [3,4 ,5].
To get the largest number in the array, you can also use apply to call the Math.max function
var arr1=[1,3,4];
alert (Math.max.apply(window,arr1)); /* The scope does not need to be window, even if it is null, Math.max.apply(this,arr1), Math.max.apply(null,arr1) */
4. Practical examples of function callbacks at work
With the above foundation, you can understand the encapsulated js callback functions at work
Background: Page A needs to use page B to select an item, and then brings back the information about this item to page A. Page A enriches itself based on this information.
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]就是选择的项目的对象的数组了(它也是个数组,里面就一个对象) }
newsee.util.url.back function is as follows:
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 function is as follows:
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, the function that needs to be called back is executed. As for how to obtain this function based on the function name in string form, see below.
//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 }
Let’s also introduce the eval() function:
The eval() function can calculate a certain string and execute the JavaScript code in it.
The return value is the value obtained by calculating string (if any). For example:
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
So the above eval('data.' key) is to execute the string "data.noticeInfo.setProjectInfo",
Because data here refers to window, so the return value It is the function window.noticeInfo.setProjectInfo()
In fact, it can be simpler. There is no need to use eval() to obtain this function, because in the include function, the item is already window.noticeInfo.setProjectInfo. Object, this object is the function we want.
(In js, functions are also objects. The function name is a reference to this function, which is almost the same as the address)
Now that we have obtained this function, we cannot return it directly. That’s it, so the above include() and findItem can be simplified like this:
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)
After testing, it was found that these two methods of obtaining functions based on function names in string form can achieve exactly the same effect.
The above is the detailed content of js function callback. For more information, please follow other related articles on the PHP Chinese website!