1 高阶函数定义
JavaScript的函数其实都指向某个变量。既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。
1 2 3 4 5 6 7 8 9
| function add(x, y, f) { return f(x) + f(y); }
x = -5; y = 6; f = Math.abs; f(x) + f(y) ==> Math.abs(-5) + Math.abs(6) ==> 11; return 11;
|
2 MapReduce
map:对集合分割运算。
reduce:对分割运算的结果进行聚合。
array.map
map()方法本身可以接受一个函数,作用在数组的每一个元素,并拼接成新的数组。是一个高阶函数。
1 2 3 4 5 6 7 8 9
| function pow(x) { return x * x; } var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]; var results = arr.map(pow); // [1, 4, 9, 16, 25, 36, 49, 64, 81] console.log(results);
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]; arr.map(String); // ['1', '2', '3', '4', '5', '6', '7', '8', '9']
|
array.reduce
再看reduce的用法。Array的reduce()把一个函数作用在这个Array的[x1, x2, x3…]上,这个函数必须接收两个参数,reduce()把结果继续和序列的下一个元素做累积计算,其效果就是:
1
| [x1, x2, x3, x4].reduce(f) = f(f(f(x1, x2), x3), x4)
|
1 2 3 4
| var arr = [1, 3, 5, 7, 9]; arr.reduce(function (x, y) { return x + y; }); // 25
|
3 filter
过滤元素
把Array的某些元素过滤掉,然后返回剩下的元素
Array的filter()也接收一个函数。filter()把传入的函数依次作用于每个元素,然后根据返回值是true还是false决定保留还是丢弃该元素。
1 2 3 4 5
| var arr = [1, 2, 4, 5, 6, 9, 10, 15]; var r = arr.filter(function (x) { return x % 2 !== 0; }); r; // [1, 5, 9, 15]
|
回调函数
filter()接收的回调函数,其实可以有多个参数。通常我们仅使用第一个参数,表示Array的某个元素。回调函数还可以接收另外两个参数,表示元素的位置和数组本身:
1 2 3 4 5 6 7
| var arr = ['A', 'B', 'C']; var r = arr.filter(function (element, index, self) { console.log(element); // 依次打印'A', 'B', 'C' console.log(index); // 依次打印0, 1, 2 console.log(self); // self就是变量arr return true; });
|
利用回调函数,除掉重复元素
1 2 3 4 5 6
| var r,arr = ['apple', 'strawberry', 'banana', 'pear', 'apple', 'orange', 'orange', 'strawberry']; r = arr.filter(function (element, index, self) { return self.indexOf(element) === index; });
|
4 sort
默认把所有的元素转换为String进行排序。可以接受比较函数进行排序。
1 2 3 4 5 6 7 8 9 10
| arr.sort(function (x, y) { if (x < y) { return -1; } if (x > y) { return 1; } return 0; }); console.log(arr); // [1, 2, 10, 20]
|
5 every
every()方法可以判断数组的所有元素是否满足测试条件。
1 2 3 4 5 6 7 8
| var arr = ['Apple', 'pear', 'orange']; console.log(arr.every(function (s) { return s.length > 0; })); // true, 因为每个元素都满足s.length>0
console.log(arr.every(function (s) { return s.toLowerCase() === s; })); // false, 因为不是每个元素都全部是小写
|
6 find
find()方法用于查找符合条件的第一个元素,如果找到了,返回这个元素,否则,返回undefined
1 2 3 4 5 6 7 8
| var arr = ['Apple', 'pear', 'orange']; console.log(arr.find(function (s) { return s.toLowerCase() === s; })); // 'pear', 因为pear全部是小写
console.log(arr.find(function (s) { return s.toUpperCase() === s; })); // undefined, 因为没有全部是大写的元素
|
7 findIndex
findIndex()和find()类似,也是查找符合条件的第一个元素,不同之处在于findIndex()会返回这个元素的索引,如果没有找到,返回-1:
1 2 3 4 5 6 7 8
| var arr = ['Apple', 'pear', 'orange']; console.log(arr.findIndex(function (s) { return s.toLowerCase() === s; })); // 1, 因为'pear'的索引是1
console.log(arr.findIndex(function (s) { return s.toUpperCase() === s; })); // -1
|
8 forEach
forEach()和map()类似,它也把每个元素依次作用于传入的函数,但不会返回新的数组。forEach()常用于遍历数组,因此,传入的函数不需要返回值:
1 2
| var arr = ['Apple', 'pear', 'orange']; arr.forEach(console.log); // 依次打印每个元素
|
9 闭包
闭包的出现,可以获取函数内部的变量且变量一直在内存当中.最简单的理解,一个作用域使用了另一个作用域中的变量。比如外层函数通过传参的方式,把某个变量传递给内层函数,就产生了闭包
函数可以作为返回值实现惰性求值
高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。
可以通过函数作为返回值,实现懒求值。
1 2 3 4 5 6 7 8 9 10 11 12
| function lazy_sum(arr) { var sum = function () { return arr.reduce(function (x, y) { return x + y; }); } return sum; }
//调用函数f时,才真正计算求和的结果:
f(); // 15
|
函数作为返回值实现循环惰性求值
感觉与Python的生成器yield惰性求值很像,这里介绍了其根本的原理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| function count() { var arr = []; for (var i=1; i<=3; i++) { arr.push((function (n) { return function () { return n * n; } })(i)); } return arr; }
var results = count(); var f1 = results[0]; var f2 = results[1]; var f3 = results[2];
f1(); // 1 f2(); // 4 f3(); // 9
|
10 回调函数与多线程异步通信
回调函数就是一个函数,它是在我们启动一个异步任务的时候就告诉它:等你完成了这个任务之后要干什么。这样一来主线程几乎不用关心异步任务的状态了,他自己会善始善终。