【JS必知必会】高阶函数详解与实战(1)

文章详细介绍了JavaScript中的reduce(),filter(),sort()函数以及高阶函数的概念,通过实例展示了这些函数在处理数组时的行为和使用技巧,包括初始值的影响以及如何自定义排序规则。
摘要由CSDN通过智能技术生成

上面是没有 initialValue 的情况,代码的执行过程如下,callback 总共调用四次。

| callback | accumulator | currentValue | currentIndex | array | return value |

| — | — | — | — | — | — |

| first call | 0 | 1 | 1 | [0, 1, 2, 3, 4] | 1 |

| second call | 1 | 2 | 2 | [0, 1, 2, 3, 4] | 3 |

| third call | 3 | 3 | 3 | [0, 1, 2, 3, 4] | 6 |

| fourth call | 6 | 4 | 4 | [0, 1, 2, 3, 4] | 10 |

有 initialValue 值

我们再来看下有 initialValue 的情况,假设 initialValue 值为 10,我们看下代码。

//koala

const arr = [0, 1, 2, 3, 4];

let sum = arr.reduce((accumulator, currentValue, currentIndex, array) => {

return accumulator + currentValue;

}, 10);

console.log( sum );

// 20

console.log( arr );

// [0, 1, 2, 3, 4]

复制代码

代码的执行过程如下所示,callback 总共调用五次。

| callback | accumulator | currentValue | currentIndex | array | return value |

| — | — | — | — | — | — |

| first call | 10 | 0 | 0 | [0, 1, 2, 3, 4] | 10 |

| second call | 10 | 1 | 1 | [0, 1, 2, 3, 4] | 11 |

| third call | 11 | 2 | 2 | [0, 1, 2, 3, 4] | 13 |

| fourth call | 13 | 3 | 3 | [0, 1, 2, 3, 4] | 16 |

| fifth call | 16 | 4 | 4 | [0, 1, 2, 3, 4] | 20 |

Array.prototype.filter


filter(过滤,筛选) 方法创建一个新数组,原始数组不发生改变。

array.filter(callback,[ thisObject]);

其包含通过提供函数实现的测试的所有元素。接收的参数和 map 是一样的,filter的callback函数需要返回布尔值true或false. 如果为true则表示通过啦!如果为false则失败,其返回值是一个新数组,由通过测试为true的所有元素组成,如果没有任何数组元素通过测试,则返回空数组。

来个例子介绍下,现在有一个数组 [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4],我们想要生成一个新数组,这个数组要求没有重复的内容,即为去重。

不使用高阶函数

const arr1 = [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4];

const arr2 = [];

for (let i = 0; i < arr1.length; i++) {

if (arr1.indexOf( arr1[i] ) === i) {

arr2.push( arr1[i] );

}

}

console.log( arr2 );

// [1, 2, 3, 5, 4]

console.log( arr1 );

// [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4]

使用高阶函数

const arr1 = [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4];

const arr2 = arr1.filter( (element, index, self) => {

return self.indexOf( element ) === index;

});

console.log( arr2 );

// [1, 2, 3, 5, 4]

console.log( arr1 );

// [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4]

filter注意点说明

callback在过滤测试的时候,一定要是Boolean值吗? 例子:

var arr = [0, 1, 2, 3];

var arrayFilter = arr.filter(function(item) {

return item;

});

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

通过例子可以看出:过滤测试的返回值只要是弱等于== true/false就可以了,而非非得返回 === true/false.

Array.prototype.sort


sort()方法用原地算法对数组的元素进行排序,并返回数组,该排序方法会在原数组上直接进行排序,并不会生成一个排好序的新数组。排序算法现在是稳定的。默认排序顺序是根据字符串Unicode码点。

// 语法

arr.sort([compareFunction])

compareFunction参数是可选的,用来指定按某种顺序进行排列的函数。注意该函数有两个参数:

参数1:firstEl

第一个用于比较的元素。

参数2:secondEl

第二个用于比较的元素。看下面的例子与说明:

// 未指明compareFunction函数

[‘Google’, ‘Apple’, ‘Microsoft’].sort(); // [‘Apple’, ‘Google’, ‘Microsoft’];

// apple排在了最后:

[‘Google’, ‘apple’, ‘Microsoft’].sort(); // [‘Google’, 'Microsoft", ‘apple’]

// 无法理解的结果:

[10, 20, 1, 2].sort(); // [1, 10, 2, 20]

//正确的结果

[6, 8, 1, 2].sort(); // [1, 2,6, 8]

// 指明compareFunction函数

‘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]

如果没有指明 compareFunction ,那么元素会按照转换为的字符串的诸个字符的Unicode位点进行排序。例如 “Banana” 会被排列到 “cherry” 之前。当数字按由小到大排序时,10 出现在 2 之前,但因为(没有指明 compareFunction),比较的数字会先被转换为字符串,所以在Unicode顺序上 “10” 要比 “2” 要靠前。

如果指明了 compareFunction ,那么数组会按照调用该函数的返回值排序。即 a 和 b 是两个将要被比较的元素:

  • 如果 compareFunction(a, b) 小于 0 ,那么 a 会被排列到 b 之前;

  • 如果 compareFunction(a, b) 等于 0 , a 和 b 的相对位置不变。备注: ECMAScript 标准并不保证这一行为,而且也不是所有浏览器都会遵守(例如 Mozilla 在 2003 年之前的版本);

  • 如果 compareFunction(a, b) 大于 0 , b 会被排列到 a 之前。

compareFunction(a, b) 必须总是对相同的输入返回相同的比较结果,否则排序的结果将是不确定的。

sort排序算法的底层实现

看了上面sort的排序介绍,我想小伙伴们肯定会对sort排序算法的内部实现感兴趣,我在sf上面搜了一下,发现有些争议。于是去查看了V8引擎的源码,发现在源码中的710行

源码地址:github.com/v8/v8/blob/…

// In-place QuickSort algorithm.

// For short (length <= 22) arrays, insertion sort is used for efficiency.

V8 引擎 sort 函数只给出了两种排序 InsertionSortQuickSort数量小于等于22的数组使用 InsertionSort,比22大的数组则使用 QuickSort,有兴趣的可以看看具体算法实现。

注意:不同的浏览器引擎可能算法实现并不同,我这里只是查看了V8引擎的算法实现,有兴趣的小伙伴可以查看下其他开源浏览器具体sort的算法实现。

如何改进排序算法实现数字正确排序呢?

对于要比较数字而非字符串,比较函数可以简单的以 a 减 b,如下的函数将会将数组升序排列,降序排序则使用b-a。

let compareNumbers= function (a, b) {

return a - b;

}

let koala=[10, 20, 1, 2].sort(compareNumbers)

console.log(koala);

// [1 , 2 , 10 , 20]

//或者

let koala=[10, 20, 1, 2].sort((a,b)=> a-b)

函数作为返回值输出


返回一个函数,下面直接看两个例子来加深理解。

isType 函数

我们知道在判断类型的时候可以通过Object.prototype.toString.call 来获取对应对象返回的字符串,比如:

let isString = obj => Object.prototype.toString.call( obj ) === ‘[object String]’;

let isArray = obj => Object.prototype.toString.call( obj ) === ‘[object Array]’;

let isNumber = obj => Object.prototype.toString.call( obj ) === ‘[object Number]’;

可以发现上面三行代码有很多重复代码,只需要把具体的类型抽离出来就可以封装成一个判断类型的方法了,代码如下。

let isType = type => obj => {

return Object.prototype.toString.call( obj ) === '[object ’ + type + ‘]’;

}

isType(‘String’)(‘123’); // true

isType(‘Array’)([1, 2, 3]); // true

isType(‘Number’)(123); // true

这里就是一个高阶函数,因为 isType 函数将 obj => { ... } 这一函数作为返回值输出。

add求和函数

前言中的面试题,用 JS 实现一个无限累加的函数 add,示例如下:

add(1); // 1

add(1)(2); // 3

add(1)(2)(3); // 6

分析面试题的结构,都是将函数作为返回值输出,然后接收新的参数并进行计算。

我们知道打印函数时会自动调用 toString()方法(如果不知道的可以去看我的这篇文章),函数 add(a) 返回一个sum(b)函数,函数 sum() 中累加计算 a = a + b,只需要重写sum.toString()方法返回变量 a 就可以了。

function add(a) {

function sum(b) { // 使用闭包

a = a + b; // 累加

return sum;

}

sum.toString = function() { // 重写toString()方法

return a;

}

return sum; // 返回一个函数

}

add(1); // 1

add(1)(2); // 3

add(1)(2)(3); // 6

如何自己创建高阶函数


前面讲了语言中内置的各种高阶函数。知道了到底啊什么是高阶函数,有哪些类型的高阶函数。那么让我们自己创建一个高阶函数吧!

假设 js 没有原生的map方法。 我们自己构建个类似map的高阶函数,从而创建我们自己的高阶函数。 假设我们有一个字符串数组,我们希望把它转换为整数数组,其中每个元素代表原始数组中字符串的长度。

const strArray=[‘js’,‘PHP’,‘JAVA’,‘C’,‘Python’];

function mapForEach(arr,fn){

const newArray = [];

for(let i = 0; i<arr.length;i++){

newArray.push({

fn(arr[i])

);

}

return newArray;

}

const lenArray = mapForEach(strArray,function(item){

return item.length;

});

console.log(lenArray);//[10,3,4,1,6]

代码分析讲解:

我们创建了一个高阶函数 mapForEach ,它接受一个数组和一个回调函数 fn。 它循环遍历传入的数组,并在每次迭代时在 newArray.push 方法调用回调函数 fn 。

最后

如果你已经下定决心要转行做编程行业,在最开始的时候就要对自己的学习有一个基本的规划,还要对这个行业的技术需求有一个基本的了解。有一个已就业为目的的学习目标,然后为之努力,坚持到底。如果你有幸看到这篇文章,希望对你有所帮助,祝你转行成功。

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值