JavaScript Learning Record day7-Higher Order Functions
@ (Learning) [javascript]
1. What is a higher-order function?
Higher-order function in English is called Higher-order function. So what is a higher order function?
JavaScript functions actually point to a variable. Since variables can point to functions and the parameters of functions can receive variables, then one function can receive another function as parameters, which is called higher-order function.
A simplest higher order function:
function add(x, y, f) {
return f(x) + f(y);
}
When we call add(-5, 6, Math.abs), parameters x, y and f receive - 5, 6 and function Math.abs, respectively. According to the function definition, we can deduce the calculation process as follows:
x = -5;
y = 6;
f = Math.abs;
f(x) + f(y) ==> Math.abs(-5) + Math.abs(6) ==> 11;
return 11;
Verify with code:
'use strict';
function add(x, y, f) {
return f(x) + f(y);
}
var x = add(-5, 6, Math.abs);
console.log(x); // 11
2. map
For example, if we have a function f(x)=x_, we can use map to implement this function on an array [1, 2, 3, 4, 5, 6, 7, 8, 9]:
Because the map() method is defined in JavaScript Array, we call Array's map() method and pass in our own function, and we get a new Array as a result:
'use strict';
function pow(x) {
return x * x;
}
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var results = arr.map(pow);
console.log(results); // [1, 4, 9, 16, 25, 36, 49, 64, 81]
Be careful:
The parameter passed in by map() is pow, which is the function object itself.
One might think that without map(), write a loop, or calculate the result:
var f = function (x) {
return x * x;
};
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var result = [];
for (var i=0; i<arr.length; i++) {
result.push(f(arr[i]));
}
Sure, but from the loop code above, we can't see at a glance that f(x) acts on every element of Array and generates a new Array from the result.
So map() as a higher-order function, in fact it abstracts the operation rules. Therefore, we can not only calculate simple f(x)=x_, but also calculate any complex function, such as converting all Array numbers into strings:
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
arr.map(String); // ['1', '2', '3', '4', '5', '6', '7', '8', '9']
It only takes one line of code.
3. reduce
Look again at the use of reduce. Array's reduce() applies a function to this Array's [x1, x2, x3...]. This function must accept two parameters. Reduc () continues the result and accumulates the next element of the sequence. Its effect is:
[x1, x2, x3, x4].reduce(f) = f(f(f(x1, x2), x3), x4)
For example, to sum an Array, you can use reduce to achieve:
var arr = [1, 3, 5, 7, 9];
result = arr.reduce(function (x, y) {
return x + y;
});
console.log(result); // 25
Exercise: Quadrature with reduce():
function product(arr) {
result = arr.reduce(function (x, y) {
return x * y;
});
return result;
}
// Test:
if (product([1, 2, 3, 4]) === 24 && product([0, 1, 2]) === 0 && product([99, 88, 77, 66]) === 44274384) {
console.log('Test pass!');
}
else {
console.log('Test failure!');
}
To transform [1, 3, 5, 7, 9] into integers 13579, reduce() can also be useful:
var arr = [1, 3, 5, 7, 9];
arr.reduce(function (x, y) {
return x * 10 + y;
}); // 13579
If we continue to improve on this example, we can find a way to turn a string 13579 into Array -[1, 3, 5, 7, 9], and then use reduce() to write a function that converts a string to Number.
Practice:
Instead of using JavaScript's built-in parseInt() function, use map and reduce operations to implement a string2int() function:
'use strict';
function string2int(s) {
// Weak Type Conversion Using js Variables
var s_length = s.length;
if (s_length == 1) {
return s * 1;
} else {
var arr = s.split("");
var result = arr.reduce(function (x, y) {
return x * 10 + y * 1;
});
return result;
}
}
// Test:
if (string2int('0') === 0 && string2int('12345') === 12345 && string2int('12300') === 12300) {
if (string2int.toString().indexOf('parseInt') !== -1) {
console.log('do not use parseInt()!');
} else if (string2int.toString().indexOf('Number') !== -1) {
console.log('do not use Number()!');
} else {
console.log('Test pass!');
}
}
else {
console.log('Test failure!');
}
Practice:
Please change the non-standard English name entered by the user into capitalized initials and standard names in other lowercase letters. Input: ['adam','LISA','barT'], output: ['Adam','Lisa','Bart'].
'use strict';
function normalize(arr) {
// return arr.map((x)=>{
// if(x.length > 0)
// {
// x = x.toLowerCase();
// x = x[0].toUpperCase() + x.substr(1);
// }
// return x;
// });
return arr.map(function (x) {
return x.substring(0, 1).toUpperCase() + x.substring(1).toLowerCase();
});
}
// Test:
if (normalize(['adam', 'LISA', 'barT']).toString() === ['Adam', 'Lisa', 'Bart'].toString()) {
console.log('Test pass!');
}
else {
console.log('Test failure!');
}
Xiao Ming hopes to use map() to turn strings into integers. His code is very concise:
'use strict';
var arr = ['1', '2', '3'];
var r;
r = arr.map(parseInt);
console.log(r);
The result is that 1, NaN, NaN, Xiao Ming is puzzled. Please help him find the reason and correct the code.
The grammar of parseInt(): parseInt ( String s , [ int radix ] ) Among them, The parameter String s, which is required, represents the string to be parsed. int radix, optional, represents the cardinality of the number to be parsed. This function uses the cardinality specified by the second parameter, and its value is between 2 and 36. If the parameter or its value is omitted, the number will be resolved on the basis of 10. If it starts with "0x" or "0X", it will be based on 16. If the parameter is less than 2 or greater than 36, parseInt() returns NaN. ["1","2","3"].map(parseInt) is equal to [parseInt(1,0),parseInt(2,1),parseInt(3,2)];
4. filter
filter is also a common operation that filters out some elements of Array and returns the remaining elements.
Similar to map(), Array's filter() also receives a function. Unlike map(), filter() acts on each element in turn with the incoming function, and then decides whether to retain or discard the element based on whether the return value is true or false.
For example, in an Array, delete even numbers and keep only odd numbers. You can write as follows:
var arr = [1, 2, 4, 5, 6, 9, 10, 15];
var r = arr.filter(function (x) {
return x % 2 !== 0;
});
console.log(r); // [1, 5, 9, 15]
To delete an empty string from an Array, you can write as follows:
var arr = ['A', '', 'B', null, undefined, 'C', ' '];
var r = arr.filter(function (s) {
return s && s.trim(); // Note: There is no trim() method for versions below IE9
});
console.log(r); // ['A', 'B', 'C']
It can be seen that the key to using filter() as a high-order function is to correctly implement a "filter" function.
callback
The callback function received by filter() can actually have multiple parameters. Usually we only use the first parameter to represent an element of Array. The callback function can also receive two other parameters, representing the location of the element and the array itself:
var arr = ['A', 'B', 'C'];
var r = arr.filter(function (element, index, self) {
console.log(element); // Print'A','B','C'in turn
console.log(index); // Print 0, 1, 2 in turn
console.log(self); // self is the variable arr
return true;
});
Using filter, the repetitive elements of Array can be subtly removed:
'use strict';
var
r,
arr = ['apple', 'strawberry', 'banana', 'pear', 'apple', 'orange', 'orange', 'strawberry'];
r = arr.filter(function (element, index, self) {
return self.indexOf(element) === index;
});
console.log(r.toString()); // apple,strawberry,banana,pear,orange
Removing duplicate elements depends on the fact that indexOf always returns the position of the first element. The position of subsequent duplicate elements is not equal to that of indexOf, so it is filtered out by filter.
Practice
Please try to filter out the prime numbers with filter():
'use strict';
function get_primes(arr) {
// To determine whether an integer m is a prime, we only need to use every integer between 2 and m-1 to remove it. If none of them can be divisible, then M is a prime.
// For a positive integer m, it must not be divisible for a positive integer in the range of (m/2, m).
// Therefore, when we judge m, there is no need to divide it by the number in that range.
var r = arr.filter(function (element, index, self) {
var i;
var result = true;
for (i = 2; i <= element / 2 ; i++) {
if (element % i == 0) {
result = false;
break;
}
}
return element < 2 ? false : result;
});
return r;
}
// Test:
var
x,
r,
arr = [];
for (x = 1; x < 100; x++) {
arr.push(x);
}
r = get_primes(arr);
if (r.toString() === [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97].toString()) {
console.log('Test pass!');
} else {
console.log('Test failure: ' + r.toString());
}
5. Sorting algorithm
Sorting is also an algorithm often used in programs. Whether bubble sorting or quick sorting is used, the core of sorting is to compare the size of two elements. If it's a number, we can compare directly, but what if it's a string or two objects? It is meaningless to directly compare the size of mathematics. Therefore, the process of comparison must be abstracted through functions. Generally, it is stipulated that for two elements x and y, if x < y, return - 1, if x = y, return 0, and if x > y, return 1. Thus, the sorting algorithm does not need to care about the specific comparison process, but directly sort according to the comparison results.
JavaScript's Array sort() method is used for sorting, but the sorting results may surprise you:
// Seemingly normal results:
['Google', 'Apple', 'Microsoft'].sort(); // ['Apple', 'Google', 'Microsoft'];
// apple came last:
['Google', 'apple', 'Microsoft'].sort(); // ['Google', 'Microsoft", 'apple']
// Ununderstandable results:
[10, 20, 1, 2].sort(); // [1, 10, 2, 20]
The second sort ranks apple s last because strings are sorted according to ASCII codes, while ASCII codes for lowercase a follow uppercase letters.
Why is the third ranking result? Can simple numbers be sorted incorrectly?
This is because Array's sort() method defaults to converting all elements to String before sorting, resulting in'10'ahead of'2' because the character'1'is smaller than the ASCII code of the character'2'.
If you don't know the default sort rule of sort(), sort the numbers directly and fall into the pit absolutely!
Fortunately, the sort() method is also a higher-order function, and it can also accept a comparison function to achieve custom sorting.
To sort by number size, we can write as follows:
'use strict';
var arr = [10, 20, 1, 2];
arr.sort(function (x, y) {
if (x < y) {
return -1;
}
if (x > y) {
return 1;
}
return 0;
});
console.log(arr); // [1, 2, 10, 20]
If we want to sort in reverse order, we can put the large number in front:
var arr = [10, 20, 1, 2];
arr.sort(function (x, y) {
if (x < y) {
return 1;
}
if (x > y) {
return -1;
}
return 0;
}); // [20, 10, 2, 1]
By default, string sorting is compared according to the size of ASCII. Now, we propose that sorting should ignore case and sort alphabetically. In order to implement this algorithm, we need not make any major changes to the existing code, as long as we can define a comparison algorithm that ignores case.
var arr = ['Google', 'apple', 'Microsoft'];
arr.sort(function (s1, s2) {
x1 = s1.toUpperCase();
x2 = s2.toUpperCase();
if (x1 < x2) {
return -1;
}
if (x1 > x2) {
return 1;
}
return 0;
}); // ['apple', 'Google', 'Microsoft']
To compare two strings by ignoring case is to first capitalize (or lower case) the strings and then compare them.
As can be seen from the above examples, the abstraction ability of higher-order functions is very powerful, and the core code can be kept very concise.
Finally, the friendship hint is that the sort() method will modify Array directly, and the result it returns is still the current Array:
var a1 = ['B', 'A', 'C'];
var a2 = a1.sort();
a1; // ['A', 'B', 'C']
a2; // ['A', 'B', 'C']
a1 === a2; // true, a1 and a2 are the same objects
Learning Reference Courses: http://www.liaoxuefeng.com