In JavaScript, functions are the first class of objects, which means that functions can be used like objects in the first class of management. Since functions are actually objects: they can be "stored" in variables, can be passed as function parameters, can be created in functions, and can be returned from functions.
Because the function is the first class object, we can use the callback function in JavaScript. In the following article, we will learn about the various aspects of the callback function. The callback function is probably the most functional programming technique in JavaScript, although it literally seems to have been a small piece of JavaScript or jquery code, but it remains a mystery to many developers. After reading this article you can learn how to use the callback function.
A callback function is a concept derived from a programming paradigm called functional programming. In simple terms, functional programming is the use of functions as variables. Functional programming--and even now--is still not widely used--it used to be seen as the esoteric skill of licensed, master-level programmers.
Fortunately, the function is a programming technique that is now fully articulated so that ordinary people like me and you can easily use it. One of the main techniques in functional programming is the callback function. In the following section you will find that implementing a callback function is as simple as passing a normal function. This technique is so simple that I often find it strange why it is often included in the chapters that tell the advanced techniques of JavaScript.
What is a callback or higher-order function
A callback function, also called a higher order function, is a function that is passed as a parameter to another function (where we call another function "Otherfunction"), and the callback function is called in otherfunction. A callback function is essentially a programming pattern (a solution created for a common problem), so using a callback function is also called a callback pattern.
The following is a simple and common example of using a callback function in jquery:
/注意到click方法中是一个函数而不是一个变量//它就是回调函数$("#btn_1").click(function() { alert("Btn 1 Clicked");});
As you can see in the previous example, we pass a function as an argument to the click Method. The click Method invokes (or executes) the function we pass to it. This is a typical use of callback functions in JavaScript, which is widely used in jquery.
Here is an example of a typical callback function in another javascript:
var friends = ["Mike", "Stacy", "Andy", "Rick"];friends.forEach(function (eachName, index){console.log(index + 1 + ". " + eachName); // 1. Mike, 2. Stacy, 3. Andy, 4. Rick});
Again, notice that we're talking about an anonymous function (a function without a name) passed to the Foreach method as a parameter.
So far, we have passed the anonymous function as an argument to another function or method. Before we look at more practical examples and write our own callback functions, let's begin by understanding how the callback function works.
How does a callback function work?
Because the function is the first object in JavaScript, we treat the function as if it were the object, so we can pass the function as if it were passed, return the function in the function, use the function in the other function. When we pass a callback function as an argument to another function, we simply pass the function definition. We did not execute the function in the parameter. We do not pass a function with a pair of execution parentheses () as we normally do.
It is important to note that the callback function will not be executed immediately. It will be "called back" (just like its name) at a particular point in time within the function that contains it. So even the first example of jquery looks like this:
//匿名函数不会再参数中被执行//这是一个回调函数 $("#btn_1").click(function(){ alert("Btn 1 Clicked");});
This anonymous function is called later in the function body. Even if there is a name, it is still acquired through the arguments object within the function that contains it.
The callback function is a closed packet
is capable of passing a ruined function as a variable to another function, the Destroy function executes at a point within the function that contains it, as if the callback function is defined in the function that contains it. This means that the callback function is essentially a closure.
As we know, a closure can enter the scope of the function that contains it, so the callback function can get the variables in the function that contains it, as well as the variables in the global scope.
Fundamentals of implementing Callback functions
The callback function is not complicated, but before we start to create and use the Destroy function, we should be familiar with several basic principles of implementing the callback function.
Use a named or anonymous function as a callback
In the previous jquery example and in the example foreach, we used the anonymous function defined by the parameter position as the callback function. This is a common magic in the use of callback functions. Another common pattern is to define a named function and pass the function name as a variable to the function. For example, the following:
//全局变量var allUserData = [];//普通的logStuff函数,将内容打印到控制台 function logStuff (userData){ if ( typeof userData === "string") { console.log(userData); } else if ( typeof userData === "object"){ for(var item in userData){ console.log(item + ": " + userData[item]); } }} //一个接收两个参数的函数,后面一个是回调函数 function getInput (options, callback){ allUserData.push(options); callback(options);}//当我们调用getInput函数时,我们将logStuff作为一个参数传递给它 //因此logStuff将会在getInput函数内被回调(或者执行) getInput({name:"Rich",speciality:"Javascript"}, logStuff);//name:Rich//speciality:Javascript
Passing parameters to the callback function
Since the callback function is simply a normal function at execution time, we can pass arguments to it. We are able to pass any property that contains its function (or global newsletter) as a parameter to the callback function. In the previous example, we passed the options as a parameter to the Destroy function. Now we pass a global variable and a local variable:
//全局变量var generalLastName = "Cliton";function getInput (options, callback){ allUserData.push (options); //将全局变量generalLastName传递给回调函数 callback(generalLastName,options);}
Ensure that the callback function is a function before executing
It is wise to check that the callback function passed as a parameter is indeed a function before the call. This is also the best time to implement the conditional callback function.
Let's refactor the GetInput function in the example above to make sure the check is appropriate.
function getInput(options, callback){ allUserData.push(options); //确保callback是一个函数 if(typeof callback === "function"){ //调用它,既然我们已经确定了它是可调用的 callback(options); }}
If there is no proper check, if there is not a callback function in the GetInput parameter, or the passed callback function is not actually a function, our code will cause the error to run.
Problem with the method of the This object as a callback function
When the callback function is a method of this object, we must change the method that executes the callback function to guarantee the context of the This object. Otherwise, if the callback function is passed to a global function, the This object will either point to the Global Window object (in the browser). Either point to the object that contains the method.
We explain in the following code:
Define an object that has some properties and a method///We will then pass the method as a callback function to another function
var clientData = { id: 094545, fullName "Not Set", //setUsrName是一个在clientData对象中的方法 setUserName: fucntion (firstName, lastName){ //这指向了对象中的fullName属性 this.fullName = firstName + " " + lastName; }} function getUserInput(firstName, lastName, callback){ //在这做些什么来确认firstName/lastName //现在存储names callback(firstName, lastName);}
In the following example of your code, when Clientdata.setusername is executed, This.fullname does not set the FullName attribute in the Clientdata object. Instead, it sets the FullName property in the Window object, because Getuserinput is a global function. This is because the this object in the global function points to the Window object.
getUserInput("Barack","Obama",clientData.setUserName);console.log(clientData,fullName); //Not Set//fullName属性将在window对象中被初始化 console.log(window.fullName); //Barack Obama
Use the call and apply functions to save this
We can use the call or Apply function to fix your problem. So far, we've learned that there are two ways to function in each javascript: Call and Apply. These methods are used to set the This object inside the function and to pass variables to this function.
The first parameter that call receives is the object that is used as this in the function, and the arguments passed to the function are passed in one pass (using commas, of course). The first parameter of the Apply function is also the object within the function as this, but the last parameter is indeed an array of values passed to the function.
The ring is complicated, so let's see how easy it is to use apply and call. To fix the problem in the previous example, I'll use the Apply function in your example below:
//注意到我们增加了新的参数作为回调对象,叫做“callbackObj”function getUserInput(firstName, lastName, callback. callbackObj){ //在这里做些什么来确认名字 callback.apply(callbackObj, [firstName, lastName]);}
Using the Apply function to correctly set the This object, we now correctly execute the callback and set the FullName property correctly in the Clientdata object:
//我们将clientData.setUserName方法和clientData对象作为参数,clientData对象会被Apply方法使用来设置this对象 getUserName("Barack", "Obama", clientData.setUserName, clientData);//clientData中的fullName属性被正确的设置console.log(clientUser.fullName); //Barack Obama
We can also use the call function, but in this example we use the Apply function.
Allow multiple callback functions
We can pass more than one callback function as a parameter to a function, just as we can pass more than one variable. Here's an example of Ajax in jquery:
function successCallback(){ //在发送之前做点什么} function successCallback(){ //在信息被成功接收之后做点什么}function completeCallback(){ //在完成之后做点什么}function errorCallback(){ //当错误发生时做点什么}$.ajax({ url:"http://fiddle.jshell.net/favicon.png", success:successCallback, complete:completeCallback, error:errorCallback});
"Callback to Hell" problem and solutions
When executing asynchronous code, regardless of the order in which the code is executed simply, the situation often becomes a heap of callback functions at many levels so that the code becomes the following scenario. These messy codes are called Callback Hell because too many callbacks make it very difficult to read the code. I took an example from Node-mongodb-native, a MONGODB driver for node. js. The code at the bottom of this section will fully explain the callback hell:
var p_client = new Db(‘integration_tests_20‘, new Server("127.0.0.1", 27017, {}), {‘pk‘:CustomPKFactory}); p_client.open(function(err, p_client) { p_client.dropDatabase(function(err, done) { p_client.createCollection(‘test_custom_key‘, function(err, collection) { collection.insert({‘a‘:1}, function(err, docs) { collection.find({‘_id‘:new ObjectID("aaaaaaaaaaaa")}, function(err, cursor) { cursor.toArray(function(err, items) { test.assertEquals(1, items.length); // Let‘s close the db p_client.close(); }); }); }); }); }); });
You should not want to encounter such a problem in your code when you encounter-you will not be experiencing this situation-here are two solutions to this problem.
- Name your functions and pass their names as callback functions instead of defining anonymous functions in the parameters of the main function.
- Modular L separates your code into modules, so you can get a piece of code around it to do certain things. Then you can import the modules into your mega-app.
Create your own callback function
Now that you've fully understood everything about the callback function in JavaScript (and I think you understand, if you don't have to reread so quickly), you see that using a callback function is so simple and powerful, you should look at your code to see if there is any place to use the callback function. The callback function will help you in the following ways:
-Avoid duplicate code (dry-do not repeat yourself)-achieve better abstraction where you have more multi-function functions (still maintain all functions)-Make your code more maintainable
-Make code easier to read
-Write functions for more specific functions
It's very easy to create your callback function. In the following example, I will create a function that reads the user information, creates a common poem with the data, and welcomes the user. This is a very complex function because it contains many if/else statements and it will have many limitations and incompatibilities in invoking the functionality required by those user data.
Instead, I implemented the Add function with the callback function, so that the main function of the user information can be done by simply passing the user's full name and gender as parameters to the callback function and performing any task.
Simply put, the Getuserinput function is versatile: it can perform callback functions that have no function.
First, create a generic poem's generating function, which will act as the callback function for the following getuserinput function
function Genericpoemmaker (name, gender) {Console.log (name + "is finer than fine wine."); Console.log ("Altruistic and noble for the modern time."); Console.log ("Always admirably adorned with the latest style."); Console.log ("A" + gender + "of unfortunate tragedies who still manages A perpetual Smile"); }//callback, the last item of the parameter, will be the Genericpoemmaker function Getuserinput (firstName, LastName, Gender, Callba, which we defined above) CK) {var fullName = FirstName + "" + lastName; Make sure the callback is a function if (typeof callback = = = "function") {//Execute the CALLBAC K function and pass the parameters to it callback (FullName, gender); }} call the Getuserinput function and use the Genericpoemmaker function as the callback function: Getuserinput ("Michael", "Fassbender", "Man", Genericpoemma Ker); Output/* Michael Fassbender is finer than fine wine. Altruistic and noble for the modern time. Always admirablyAdorned with the latest style. A man of unfortunate tragedies who still manages a perpetual smile. */
Since the Getuserinput function is only responsible for extracting the data, we can pass any callback function to it. For example, we can pass a GreetUser function:
unction greetUser(customerName, sex) { var salutation = sex && sex === "Man" ? "Mr." : "Ms."; console.log("Hello, " + salutation + " " + customerName);}// 将greetUser作为一个回调函数getUserInput("Bill", "Gates", "Man", greetUser);// 这里是输出Hello, Mr. Bill Gates
We called the exact same getuserinput function, but this time we've done a completely different task.
As you can see, the callback function is magical. Even if the previous example is relatively simple, imagine how much effort can be saved, your code will become more abstract, all it takes is to start using the Destroy function. Go ahead and use it boldly.
Callback functions are often used in JavaScript programming in several ways, especially in modern web application development and libraries and frameworks:
- Asynchronous calls (such as reading files, making HTTP requests, etc.)
- Time Listener/Processor
- SetTimeout and SetInterval methods
- General: Thin Code
Conclusion
JavaScript callback functions are wonderful and powerful, and they provide many benefits for your Web applications and code. You should use it when you need it, or use a callback function to refactor your code for the abstraction, maintainability, and readability of your code.
Understanding and using callback functions in JavaScript