// global variable var allUserData = []; // generic logStuff function that prints to console 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]); } } } // A function that takes two parameters, the last one a callback function function getInput (options, callback) { allUserData.push (options); callback (options); } // When we call the getInput function, we pass logStuff as a parameter. // So logStuff will be the function that will called back (or executed) inside the getInput function getInput ({name:"Rich", speciality:"JavaScript"}, logStuff); // name: Rich // speciality: JavaScript
2、传递参数给回调函数
因为回调函数在执行的时候就和一般函数一样,我们可以传递参数给它。可以将包含函数的任何属性(或全局的属性)作为参数传递回调函数。在上一个例子中,我们将包含函数的options作为参数传递给回调函数。下面的例子让我们传递一个全局变量或本地变量给回调函数:
//Global variable var generalLastName = "Clinton"; function getInput (options, callback) { allUserData.push (options); // Pass the global variable generalLastName to the callback function callback (generalLastName, options); }
3、在执行之前确保回调是一个函数
在调用之前,确保通过参数传递进来的回调是一个需要的函数通常是明智的。此外,让回调函数是可选的也是一个好的实践。
让我们重构一下上面例子中的getInput函数,确保回调函数做了适当的检查。
function getInput(options, callback) { allUserData.push(options); // Make sure the callback is a function if (typeof callback === "function") { // Call it, since we have confirmed it is callable callback(options); } }
如果getInput函数没有做适当的检查(检查callback是否是函数,或是否通过参数传递进来了),我们的代码将会导致运行时错误。
4、使用含有this对象的回调函数的问题
当回调函数是一个含有this对象的方法时,我们必须修改执行回调函数的方法以保护this对象的内容。否则this对象将会指向全局的window对象(如果回调函数传递给了全局函数),或指向包含函数。让我们看看下面的代码:
// Define an object with some properties and a method // We will later pass the method as a callback function to another function var clientData = { id: 094545, fullName: "Not Set", // setUserName is a method on the clientData object setUserName: function (firstName, lastName) { // this refers to the fullName property in this object this.fullName = firstName + " " + lastName; } } function getUserInput(firstName, lastName, callback) { // Do other stuff to validate firstName/lastName here // Now save the names callback (firstName, lastName); }
在下面的示例代码中,当clientData.setUserName被执行时,this.fullName不会设置clientData 对象中的属性fullName,而是设置window 对象中的fullName,因为getUserInput是一个全局函数。出现这种现象是因为在全局函数中this对象指向了window对象。
getUserInput ("Barack", "Obama", clientData.setUserName); console.log (clientData.fullName);// Not Set // The fullName property was initialized on the window object console.log (window.fullName); // Barack Obama
5、使用Call或Apply函数保护this对象
我们可以通过使用 Call 或 Apply函数来解决前面示例中的问题。到目前为止,我们知道JavaScript中的每一个函数都有两个方法:Call和Apply。这些方法可以被用来在函数内部设置this对象的内容,并内容传递给函数参数指向的对象。
Call takes the value to be used as the this object inside the function as the first parameter, and the remaining arguments to be passed to the function are passed individually (separated by commas of course). The Apply function's first parameter is also the value to be used as the thisobject inside the function, while the last parameter is an array of values (or the arguments object) to pass to the function. (该段翻译起来太拗口了,放原文自己体会)
这听起来很复杂,但让我们看看Apply和Call的使用是多么容易。为解决前面例子中出现的问题,我们使用Apply函数如下:
//Note that we have added an extra parameter for the callback object, called "callbackObj" function getUserInput(firstName, lastName, callback, callbackObj) { // Do other stuff to validate name here // The use of the Apply function below will set the this object to be callbackObj callback.apply (callbackObj, [firstName, lastName]); }
通过Apply函数正确地设置this对象,现在我们可以正确地执行回调函数并它正确地设置clientData对象中的fullName属性。