JavaScript高阶函数和数组函数map, forEach, fill, reduce, filter, sort,

高阶函数 (higher-order function)

一个普通函数:

function hello(arg) {
	return value;
}

如果一个函数接收另一个函数(!)作为参数,或者一个函数返回一个新的函数(!),那么此函数为高阶函数。上面的例子,如果argvalue函数, 那么hello 函数为高阶函数

1. 传递一个函数给函数

function sing(callback) {
	console.log("la la la la");
	if (callback instanceof Function) {
		callback();
	}
}
function meow() {
	console.log("meow meow");
}

sing();
// expected output: la la la la

sing(meow);
// expected output: 
// la la la la
// meow meow

下面的代码直接传递整个匿名函数定义给sing函数:

sing(function() { console.log("meow meow"); });

2. 函数返回新的函数 (function factory 函数工厂)

function multiplier(factor) {
	return function(x) {
		return x * factor;
	}
}

使用 arrow function,上面的代码简化为:

function multiplier(factor) {
	return x => x * factor;
	}
}

高阶函数multiplier函数同时也是一个closure闭包函数,测试如下:

let doubler = multiplier(2);
> undefined
doubler;
> f(x) {
     return x * factor;
  }
doubler(6)
> 12  

数组的高阶函数

数组可使用的高阶函数有很多,最常用的有如下几个函数:

1. map()

map用于传递一个函数给数组,该函数应用于数组中的每一个元素,然后并不改变原来的数组,而是创建并返回一个新的数组

let vals = [4, 8, 1, 2, 9];
console.log(vals);  // 1

function doubler(x) {
    return x*2;
}

let doubled = vals.map(doubler);
console.log(vals);  // 2
console.log(doubled);  // 3

使用arrow function 简化如下:

let vals = [4, 8, 1, 2, 9];
console.log(vals);  // 1
let doubled = vals.map(x => x * 2);  // 箭头函数
console.log(vals);  // 2
console.log(doubled);  // 3

输出如下:

(5) [4, 8, 1, 2, 9]        // 1
(5) [4, 8, 1, 2, 9]        // 2
(5) [8, 16, 2, 4, 18]      // 3

由于需要创建新数组,所以performance不一定比得上使用for循环,但是使用高阶函数能使code看起来更简洁。

2. forEach()

forEachmap 都对数组中的每一个元素进行操作,都不改变原始数组。区别是: forEach 返回 undefined, map返回一个新数组。
forEach 典型应用场合:将数组中的每个元素存储到数据库中,不返回任何值:

chars = ['Hello' , 'world!!!'] ;
var retVal = chars.forEach(function(word){
  console.log("Saving to db: " + word) 
})
console.log(retVal) //undefined

运行结果:

Saving to db: Hello
Saving to db: world!!!
undefined

map 例子:

 chars = ['Hello' , 'world!!!'] ;
    
 var lengths = chars.map(function(word){
   return word.length
 }) 
    
 console.log(lengths) // 新建数组: [5,8]

forEachmap 都不改变原始数组:

let a = [1, 2, 3];
a.forEach(i => i + 1);

let b = [1, 2, 3];
b.map(i => i + 1);

console.log(a);  // [1, 2, 3]
console.log(b);  // [1, 2, 3]

下面的例子输出数组中的每一个元素:

let a = [1, 2, 3];
let x = a.forEach((i) => console.log(i));
console.log(x);

console.log("---------");
let b = [1, 2, 3];
const y = b.map((i) => console.log(i));
console.log(y);

运行结果:

1
2        
3        
undefined
---------
1        
2
3
[ undefined, undefined, undefined ]

3. filter()

filter:过滤,对数组中的每一个元素进行筛选过滤,保留符合条件的元素。filter()函数返回新的数组

例 1

过滤掉数组中的奇数,保留偶数:

let vals = [5, 4, 9, 2 , 1];
function isEven(num) {
    return num % 2 === 0;
}
vals = vals.filter(x => x % 2 === 0);
console.log(vals);

使用箭头函数:

let vals = [5, 4, 9, 2 , 1];
vals = vals.filter(x => x % 2);
console.log(vals);

输出结果:[4, 2]

例 2

将数组中的falsey值过滤出去,仅保留truthy值:

let vals = [5, 4, undefined, 9, 2 , 1];
vals = vals.filter(x => x);
console.log(vals);

输出:[5, 4, 9, 2, 1]

例 3

提取字符串中的单词:

let s = "It was  a dark and stormy night.";
let words = s.split(" ");
console.log(words);
// expeted output: ["It", "was", "", "a", "dark", "and", "stormy", "night."]

wasa 之间有两个空格,所以结果数组多了一个空字符串,使用filter 函数过滤结果数组中的空字符串:

let s = "It was  a dark and stormy night.";
let words = s.split(" ").filter(word => word.length);
console.log(words);
// expeted output: ["It", "was", "a", "dark", "and", "stormy", "night."]

4. reduce()

reduce 大意是说,将数组中的所有元素看作一个整体,找出实质,将数组精简(reduce)为单个输出。

例1

const array1 = [1, 2, 3, 4];
const reducer = (accumulator, currentValue) => accumulator + currentValue;

// 1 + 2 + 3 + 4
console.log(array1.reduce(reducer));
// expected output: 10

// 5 + 1 + 2 + 3 + 4
console.log(array1.reduce(reducer, 5));
// expected output: 15

参数 accumulator 在对数组迭代的过程中一直存在。

例 2

不使用reduce,下面的初始代码对数组求和:

let vals = [5, 4, 1, 2 , 9];
let sum = 0;
for (let i = 0; i < vals.length; i++) {
    sum += vals[i];
}
console.log(sum);

使用 ES6 语法:

let vals = [5, 4, 1, 2 , 9];
let sum = 0;
for (let val of vals) {
    sum += val;
}
console.log(sum);

如果使用reduce, 代码如下:

let vals = [5, 4, 1, 2 , 9];
function sum(acc, val) {
    return acc + val;
}
let answer = vals.reduce(sum);
console.log(answer);

如果将语句:
let answer = vals.reduce(sum);
修改为:
let answer = vals.reduce(sum + 10); 将输出31, 这里 10为指定初始值。如果不指定此值,初始值默认为数组的第1个元素。
使用 arrow function 改写code:

let vals = [5, 4, 1, 2 , 9];
let answer = vals.reduce((acc + val) => acc + val);
console.log(answer);

例 3

找出数组中最大的元素:

let vals = [5, 4, 1, 9 , 1];
function findMax(acc, val) {
    if (acc < val) {
        acc = val;
    }
    return acc;
}
let biggest = vals.reduce(findMax);
console.log(biggest);

使用 arrow function:

let vals = [5, 4, 1, 9 , 1];
let biggest = vals.reduce((acc, val) => {
    if (acc < val) {
        acc = val;
    }
    return acc;
});
console.log(biggest);

使用二元操作符进一步简化code:

let vals = [5, 4, 1, 9 , 1];
let biggest = vals.reduce((a, b) => a > b ? a : b);
console.log(biggest);

下面的代码返回2020 为初始值,找出数组中最大的元素, 如果没有元素的值大于20, 则返回20:

let vals = [5, 4, 1, 9 , 1];
let biggest = vals.reduce((a, b) => a > b ? a : b, 20);
console.log(biggest);

5. sort()

排序,默认以升序排列,从小到大,返回修改后的已存在的数组

例 1

let vals = [5, 4, 9, 2, 1];
vals.sort();
console.log(vals);
// expected output: [1, 2, 4, 5, 9]

例 2

可以直接对字符串,字符等这些显而易见的元素排序,但是对对象数组排序无效:

let vals = [{x:4, y:3}, {x:1, y:7}];
console.log(vals);
// output: [{x:4, y:3}, {x:1, y:7}]

要对这种类型的值排序,需要自己提供比较函数给sort()函数,因为这个原因,sort是高阶函数。

let vals = [{x:2, y:10}, {x:5, y:6}];
function compare(a, b) {
    return a.y - b.y;
}
vals.sort(compare);
console.log(vals);
// output: [{x:5, y:6}, {x:2, y:10}];

例 3

let s = "It was  a dark and stormy night.";
let words = s.split(" ").filter(word => word.length);
console.log(words);
// expeted output: ["It", "was", "a", "dark", "and", "stormy", "night."]

对结果数组中的单词按字符串长度排序:

let s = "It was  a dark and stormy night.";
let words = s.split(" ").filter(word => word.length);
words.sort((a, b) => (a.length - b.length));
console.log(words);
// expeted output: ["a", "It", "was", "and", "dark", "stormy", "night."]

6. every()

every() 方法测试一个数组内的所有元素是否都能通过指定函数的测试。它返回一个布尔值。

const isBelowThreshold = (currentValue) => currentValue < 40;

const array1 = [1, 30, 39, 29, 10, 13];

console.log(array1.every(isBelowThreshold));
// Expected output: true

另一个数据库操作的例子:

Simple SELECT queries

// Find all users
const users = await User.findAll();
console.log(users.every(user => user instanceof User)); // true

数组函数 fill()

常用的函数还有一个fill(),非高阶函数,直接使用静态值修改数组中的元素,然后返回修改后的数组
语法:

fill(value)
fill(value, start)
fill(value, start, end)

例子:

const array1 = [1, 2, 3, 4];

// fill with 0 from position 2 until position 4
console.log(array1.fill(0, 2, 4));
// expected output: [1, 2, 0, 0]

// fill with 5 from position 1
console.log(array1.fill(5, 1));
// expected output: [1, 5, 5, 5]

console.log(array1.fill(6));
// expected output: [6, 6, 6, 6]

如下的code生成一个含有100个随机数元素的数组:

let vals = Array(100).fill().map(Math.random);
console.log(vals);

[1] https://www.youtube.com/watch?v=H4awPsyugS0

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值