JS callback function
We pass a function as a value to another function, and execute the function in another function. This function is called a callback function. In JS we have a convention to write the callback function parameter as callback
- The callback function we use all the time
- Iterating methods in arrays (forEach, replace…)
- Timers (setTimeout, setInterval)
- Success function in AJAX request in JQ
- DOM2 event (addEventListenter)
function func(callback) {
// callback => anonymous
for (let i = 0; i < 5; i++) {
// callback(i); //=> Pass the value of I in each loop as an argument to Anonymous, so anonymous is executed 5 times in total. Each execution can obtain the value of I passed based on the parameter index
let res = callback.call(document, i);
// res is the result returned by each anonymous execution
if (res === false) {
// Accept the result of the callback function, the end of the control loop
break;
};
};
};
func(function anonymous(index) {
if (index >= 3) {
return false;
}
return The '@' + index;
});
Copy the code
During the func function execution, we can manipulate the callback function “as much as we like”
- It can be executed zero to multiple times
- You can also pass arguments to the callback function
- You can also change the “THIS” inside
- You can also accept the return of the function execution
To make better use of the callback function, we use the callback function to wrap a powerful _each method
- Ideas:
- _EACH([VALUE],[CALLBACK],[CONTEXT]), we can pass three parameters
- You can iterate through arrays of numbers, class arrays, and objects, and execute [CALLBACK] on each iteration
- Each time the callback is executed, the result of the current iteration (current item \ index) is passed to the callback
- A third argument is supported to change the reference to THIS in the callback (not passed, default is WINDOW).
- Support callback function return value, each return value will be the current collection of the value of the value of the replacement; If the callback returns FALSE (which it must), the loop ends
// Check whether it is an array or a class array
function isArrayLike(obj) {
letlength = !! obj && ("length" in obj) && obj.length;
return Array.isArray(obj) || length === 0| | -typeof length === "number" && length > 0 && (length - 1) in obj);
}
function _each(obj, callback, context = window) {
obj = _cloneDeep(obj); //=> Make a deep clone of the original data. The later operations are the results of the clone, and the original data will not be changed
// Verify parameter validity
if (obj == null) {
//=>null undefined
/ / manual throws an exception information, once thrown, console complains, the following code is not executed the Error/TypeError/ReferenceError/SyntaxError...
throw new TypeError('OBJ must be an object/array/class array! ');
}
if (typeofobj ! = ="object") {
throw new TypeError('OBJ must be an object/array/class array! ');
}
if (typeofcallback ! = ="function") {
throw new TypeError('CALLBACK must be a function! ');
}
// Start loop (array and class array based on FOR loop, object loop based on FOR IN)
if (isArrayLike(obj)) {
// Array or class array
for (let i = 0; i < obj.length; i++) {
// Each iteration executes the callback function, passing the argument that the current iteration and the corresponding index are iterated
// And change its THIS
// RES is the return value of the callback function
let res = callback.call(context, obj[i], i);
if (res === false) {
// Return FALSE to end the loop
break;
}
if(res ! = =undefined) {
// If there is a return value, replace this item in the current array
obj[i] = res;
}
}
} else {
/ / object
for (let key in obj) {
if(! obj.hasOwnProperty(key))break;
let res = callback.call(context, obj[key], key);
if (res === false) break;
if(res ! = =undefined) obj[key] = res;
}
}
return obj;
}
Copy the code
Wrapping _each also uses the _cloneDeep function, which we also wrapped ourselves
Deep cloning, shallow cloning is often asked in our interview, here we also have a further understanding
- Shallow clone: only the first level of a copy assigned to the new array, we generally implement array cloning is shallow clone
- Deep clone: not only does the first level clone a copy of the new array, but if there are multiple levels in the original array, then each level clone is assigned to each level of the new array
- The method of realizing shallow clone
let arr = [10.20[30.40]].
let arr1 = arr.slice(0);// Assign an assignment to the new array arr1 using the slice method in the array
let arr2 = arr.concat();// Concatenate an array with the concat method, which is also equivalent to copying an array
let arr3 = [...arr];// Assign a copy of arR to the new array with the remainder operator
Copy the code
- Implement deep cloning
// json.stringify (arr) turns the original object into a string (removing the heap-heap-nested relationship)
//JSON.parse(...) After converting the string to a new object, the browser reopens memory to store the information
let arr4 = JSON.parse(JSON.stringify(arr));
Copy the code
But json.stringify does not handle all values efficiently:
- The re becomes empty
- The function /undefined/Symbol is null
- Date format data will no longer be in date object format based on PARSE after it becomes a string
- But it doesn’t affect numbers/strings/booleans/NULL/normal objects/array objects, etc
- In this way, the cloned information differs from the original data
- So we encapsulated a method that could be used for deep cloning
function _cloneDeep(obj) {
// If the Symbol is not an object, it returns the original value.
if (obj === null) return null;
if (typeofobj ! = ="object") return obj;
// Filter out special objects (regular objects or date objects) : create a new instance of the current class using the original value, so that the cloned instance is the new one, but with the same value as before
if (obj instanceof RegExp) return new RegExp(obj);
if (obj instanceof Date) return new Date(obj);
// If we pass an array or object, we need to create a new array or object to store the original data
// obj.constructor gets the current value (Array/Object)
let cloneObj = new obj.constructor;
for (let key in obj) {
// Loop over each item in the original data, assigning each item to the new object
if(! obj.hasOwnProperty(key))break;
cloneObj[key] = _cloneDeep(obj[key]);
}
return cloneObj;
}
Copy the code
This article is formatted using MDNICE