## 1 高阶函数定义 JavaScript的函数其实都指向某个变量。既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。 ``` 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()方法本身可以接受一个函数,作用在数组的每一个元素,并拼接成新的数组。是一个高阶函数。 ``` 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()把结果继续和序列的下一个元素做累积计算,其效果就是: ``` [x1, x2, x3, x4].reduce(f) = f(f(f(x1, x2), x3), x4) ``` ``` var arr = [1, 3, 5, 7, 9]; arr.reduce(function (x, y) { return x + y; }); // 25 ``` ## 3 filter ### 过滤元素 把Array的某些元素过滤掉,然后返回剩下的元素 Array的filter()也接收一个函数。filter()把传入的函数依次作用于每个元素,然后根据返回值是true还是false决定保留还是丢弃该元素。 ``` 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的某个元素。回调函数还可以接收另外两个参数,表示元素的位置和数组本身: ``` 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; }); ``` 利用回调函数,除掉重复元素 ``` 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进行排序。可以接受比较函数进行排序。 ``` 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()方法可以判断数组的所有元素是否满足测试条件。 ``` 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 ``` 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: ``` 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()常用于遍历数组,因此,传入的函数不需要返回值: ``` var arr = ['Apple', 'pear', 'orange']; arr.forEach(console.log); // 依次打印每个元素 ``` ## 9 闭包 > 闭包的出现,可以获取函数内部的变量且变量一直在内存当中.最简单的理解,一个作用域使用了另一个作用域中的变量。比如外层函数通过传参的方式,把某个变量传递给内层函数,就产生了闭包 > ### 函数可以作为返回值实现惰性求值 高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。 可以通过函数作为返回值,实现懒求值。 ``` function lazy_sum(arr) { var sum = function () { return arr.reduce(function (x, y) { return x + y; }); } return sum; } //调用函数f时,才真正计算求和的结果: f(); // 15 ``` ### 函数作为返回值实现循环惰性求值 > 感觉与Python的生成器yield惰性求值很像,这里介绍了其根本的原理。 ``` 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 回调函数与多线程异步通信 回调函数就是一个函数,它是在我们启动一个异步任务的时候就告诉它:等你完成了这个任务之后要干什么。这样一来主线程几乎不用关心异步任务的状态了,他自己会善始善终。