JS函数
高阶函数
高阶函数英文叫Higher-order function。那么什么是高阶函数?
JavaScript的函数其实都指向某个变量。既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。
所谓函数引用、对象引用、函数名其实都是内存中的一个地址,这个地址指向了某个函数或对象或方法,谁拿到了这个地址,谁就拥有了调用函数、调用方法的权利,所以所谓传入函数作为参数,其实就是把这个地址传给了另外一个函数,让另外一个函数拥有操作这个函数的权利
这部分是从前没有写到过的,需要多多理解。(array)的高阶函数主要有:
- map/reduce
- filter
- sort
- every find findIndex forEach 等
其中,需要注意的是
- map
arr.map(String);
这种用法? - sort 数字array的比较需要用到高阶函数
在练习中,学到了:
- 字符串转数字,用位运算速度快代码少,推荐。
负十六进制数字符串转换为数字时。应首先将任何其转换为String(例如通过 + "" ),然后使用一元运算符或带基数的parseInt解析为数字。但是结果不是NaN的数值时,使用parseFloat更为合适。
JavaScript字符串转数字的5种方法及其陷阱
原文converting-strings-to-number-in-javascript-pitfalls - string的方法,注意记得带(),不然会报错。
JS字符串方法
1. map/reduce
- map的用法
- 由于map()方法定义在JavaScript的Array中,我们调用Array的map()方法,传入我们自己的函数,传出一个新的Array作为结果
- 注意:map()传入的参数是pow,即函数对象本身。例:
- 用map()求平方
- 把Array的所有数字转为字符串:
//***************1*******************
function pow(x) {
return x * x;
}
var arr = [1, 23, 4];
var res = arr.map(pow);
console.log(res);
//***************2*******************
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
arr.map(String); // ['1', '2', '3', '4', '5', '6', '7', '8', '9']
只需要一行代码。
(・∀・(・∀・(・∀・*)可是String也不是一个函数对象啊?
- reduce的用法
- 接收一个函数对象,这个函数必须接收两个参数,递归执行。例子:
- 利用reduce求积
- 利用reduce将数组转为一个十进制数
- 接收一个函数对象,这个函数必须接收两个参数,递归执行。例子:
// ***************reduce*****************
// ***************1*****************利用reduce求积
function product(arr) {
return arr.reduce(function (x, y) {
return x * y;
});
}
// 测试:
if (product([1, 2, 3, 4]) === 24 && product([0, 1, 2]) === 0 && product([99, 88, 77, 66]) === 44274384) {
console.log('测试通过!');
}
else {
console.log('测试失败!');
}
//***************2*****************利用reduce将数组转为一个十进制数
function reduce(x, y) {
return x * 10 + y;
}
var arr = [1, 3, 5, 7, 9];
var res = arr.reduce(reduce);
console.log(res);
- 三个练习
- 不要使用JavaScript内置的parseInt()函数,利用map和reduce操作实现一个string2int()函数
// ***************练习*****************
// 练习:不要使用JavaScript内置的parseInt()函数,利用map和reduce操作实现一个string2int()函数:
function string2int(s) {
// var res=+s;
return +s;//这里直接转换就可以了,为什么还要用map和reduce
}
// 测试:
if (string2int('0') === 0 && string2int('12345') === 12345 && string2int('12300') === 12300) {
if (string2int.toString().indexOf('parseInt') !== -1) {
console.log('请勿使用parseInt()!');
} else if (string2int.toString().indexOf('Number') !== -1) {
console.log('请勿使用Number()!');
} else {
console.log('测试通过!');
}
}
else {
console.log('测试失败!');
}
- 请把用户输入的不规范的英文名字,变为首字母大写,其他小写的规范名字。输入:['adam', 'LISA', 'barT'],输出:['Adam', 'Lisa', 'Bart']
// 请把用户输入的不规范的英文名字,变为首字母大写,其他小写的规范名字。输入:['adam', 'LISA', 'barT'],输出:['Adam', 'Lisa', 'Bart']。
function normalize(arr) {
var res = arr.map(rename);
return res;
}
function rename(s) {
s = s.toLowerCase();
if (s.length !== 0) {
s = s[0].toUpperCase() + s.substring(1, s.length);//这里一开始忘记些toUpperCase()的括号了
}
return s;
}
// 测试:
if (normalize(['adam', 'LISA', 'barT']).toString() === ['Adam', 'Lisa', 'Bart'].toString()) {
console.log('测试通过!');
}
else {
console.log('测试失败!');
}
- 小明希望利用map()把字符串变成整数
// 小明希望利用map()把字符串变成整数,他写的代码很简洁:
// 结果竟然是1, NaN, NaN,小明百思不得其解,请帮他找到原因并修正代码。
// 提示:参考Array.prototype.map()的文档。
var arr = ['1', '2', '3'];
var r;
// r = arr.map(parseInt);
r = arr.map(x => {
return parseInt(x)
});
console.log(r);
2. filter
Array的filter()也接收一个函数。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是true还是false决定保留还是丢弃该元素。
用filter()这个高阶函数,关键在于正确实现一个“筛选”函数。
- 回调函数
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;
});
利用filter,可以巧妙地去除Array的重复元素:
// array去重
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());
- 练习:请尝试用filter()筛选出素数:
(・∀・(・∀・(・∀・*)虽然写的是arr,但是注意filter()接收的回调函数第一个传入的参数是Array的某个元素,不是整个array;整个array是第三个参数。
// 用filter()筛选出素数:
function get_primes(arr) {
//虽然写的是arr,但是注意filter()接收的回调函数第一个传入的参数是Array的某个元素,不是整个array;整个array是第三个参数
return arr.filter(function (element) {
//1既不是质数也不是合数
if(element===1)
return false;
var i;
//从2开始,2是质数
for (i = 2; i < element; i++) {
if (element % i === 0) {
return false;
}
}
return true;
});
}
// 测试:
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('测试通过!');
} else {
console.log('测试失败: ' + r.toString());
}
3. sort
sort方法在使用中要注意它默认是对字符串的ASCII码进行排序:
Array的sort()方法默认把所有元素先转换为String再排序,结果'10'排在了'2'的前面,因为字符'1'比字符'2'的ASCII码小。
如果需要排序数字类型的array,需要接收一个比较函数来实现自定义的排序。
这个比较函数是靠取值来确定顺序的(正、负、0)
通常在代码中常写(1、-1、0)
Reference/Global_Objects/Array/sort
If compareFunction(a, b) is less than 0, sort a to a lower index than b, i.e. a comes first.
If compareFunction(a, b) returns 0, leave a and b unchanged with respect to each other, but sorted with respect to all different elements. Note: the ECMAscript standard does not guarantee this behaviour, and thus not all browsers (e.g. Mozilla versions dating back to at least 2003) respect this.
If compareFunction(a, b) is greater than 0, sort b to a lower index than a.
compareFunction(a, b) must always return the same value when given a specific pair of elements a and b as its two arguments. If inconsistent results are returned then the sort order is undefined.
4. Array
对于数组,除了map()、reduce、filter()、sort()这些方法可以传入一个函数外,Array对象还提供了很多非常实用的高阶函数。
- every
every()方法可以判断数组的所有元素是否满足测试条件。
(・∀・(・∀・(・∀・*)和filter类似,但every返回的是布尔值,filter返回的是筛选后的array。 - find
find()方法用于查找符合条件的第一个元素,如果找到了,返回这个元素,否则,返回undefined。 - findIndex
findIndex()和find()类似,也是查找符合条件的第一个元素,不同之处在于findIndex()会返回这个元素的索引,如果没有找到,返回-1 - forEach
forEach()和map()类似,它也把每个元素依次作用于传入的函数,但不会返回新的数组。forEach()常用于遍历数组,因此,传入的函数不需要返回值。