[原]JS原生数组方法的用法及其实现(二)

本文原载于CSDN

(接上一篇,过去了好几个月了,突然想到这里还留了一个坑。。。)

九、entries()

entries() 方法返回一个新的Array Iterator对象,该对象包含数组中每个索引的键/值对。

entries()函数返回的是一个数组的迭代对象,与Generator 函数(可以参考阮一峰大叔写的ES6入门中的介绍Generator 函数)的返回结果是一样的,所以直接通过 .next()依次得到结果,其中。如下

let arr = [1, 2, 3]
let ent = arr.entries()
console.log(ent.next()) // {value: Array(2), done: false}
// 其中,value是一个数组,为 [0, 1],分别代表下标,以及下标对应的值
// done 是一个Boolean类型的值,代表遍历是否以经结束
console.log(ent.next()) // {value: Array(2), done: false}
console.log(ent.next()) // {value: Array(2), done: false}
console.log(ent.next()) // {value: undefined, done: true}
// 遍历结束,done值变为true

实现方法的核心就是Generator 函数。利用其的特性来完成数组的迭代。

Array.prototype.myEntries = function* () {
// function* () 是Generator函数的定义方式
for (var key of this) {
// 遍历数组,返回一个包含下标和对应值的数组
yield [key - 1, this[key - 1]];
}
}

十、find()

find() 方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined。

find()类似于some(),不同的是,some()是判断目标数组中是否含有满足条件的值,返回一个Boolean类型的值,而find()是找到目标数组中满足条件的第一个值,并返回该值。使用方法如下:

let arr = [1, 2, 3]
arr.find(ele => ele > 2) // 3
// => es6箭头函数
arr.find(ele => ele > 5) // undefined
arr.find(ele => ele > 5) // Uncaught TypeError: undefined is not a function
// find()中的参数函数依旧接收三个参数,分别为 value, index, arr

可见,find()依旧是通过遍历来查找符合条件的值,实现如下:

Array.prototype.myFind = function(fn, callback) {
let len = this.length
if(typeof fn === 'function') {
// 参数必须类型为函数
for(let i = 0; i < len; i ++) {
if(fn.call(callback, this[i], i, this)) {
return this[i]
}
}
} else {
throw new Error(`${fn} is not a funciton`)
// 抛出一个错误
}
}

十一、findIndex()

findIndex()方法返回数组中满足提供的测试函数的第一个元素的索引。否则返回-1。

findIndex()find()唯一的区别就是一个返回元素本身,一个返回索引。使用方法如下:

let arr = [1, 2, 3]
arr.findIndex(ele => ele > 2) // 2
arr.findIndex(ele => ele > 3) // -1
arr.findIndex() // Uncaught TypeError: undefined is not a function
// findIndex()中的参数函数依旧接收三个参数,分别为 value, index, arr

实现方法与find()的实现也是仅有一点差别,如下:

Array.prototype.myFindIndex = function(fn, callback) {
let len = this.length
if(typeof fn === 'function') {
// 参数必须类型为函数
for(let i = 0; i < len; i ++) {
if(fn.call(callback, this[i], i, this)) {
return i
}
}
} else {
throw new Error(`${fn} is not a funciton`)
// 抛出一个错误
}
return -1
// 没有查找到符合条件的,返回-1,find()的实现中没写,默认返回 undefined
}

十二、flat()

flat() 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。

刚看到的时候一脸懵逼,啥时候居然有这么厉害的方法了。。。
flat()照我的理解就是将一个多维数组转换为低维数组,以及去掉其中的空项,同时,此方法不会改变原数组。使用如下:

// flat 接收一个参数,默认参数值为 1
let arr1 = [1, 2, 3, [4, 5, 6]]
let arr2 = [1, 2, [3, [4, 5, [6, 7]]]]
let arr3 = [1, , 3, 4, undefined, null] // 稀疏数组
arr1.flat() // [1, 2, 3, 4, 5, 6]
arr2.flat() // [1, 2, 3, [4, 5, [6, 7]]]
// 采用默认值 1,只提取了一层的多维数组,让维度从4变为3
arr2.flat(3) // [1, 2, 3, 4, 5, 6, 7]
arr3.flat() // [1, 3, 4, undefined, null]
// 只去掉了空项,而不管值是否为 undefined,或 null

实现的话,二维降一维很简单,通过解构就可以实现,那么多维降维,就需要多次解构,但是这个次数是不一定的,所以可以通过递归实现。实现如下:

Array.prototype.myFlat = function(src = 1, callback) {
let newArr = [], // 存放生成的新数组
oArr = [] // 临时数组
if(typeof src === 'number') {
if (src === 1) {
oArr = [].concat(...this)
// 通过解构对数组降维,每次降一维
} else {
oArr = [].concat(...this.myFlat(src - 1))
// 递归降维
}
} else {
throw new Error(`${src} is not a number.`)
}
oArr.forEach(ele => newArr.push(ele))
// 通过forEach去掉空项,map也可以实现
return newArr
}

以上有个缺陷,就是对输入的过大的参数没有处理。

十三、includes()

includes() 方法用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回false。

看到这个方法就想到了some(),二者有异曲同工之妙,some()是判断指定数组是否有元素符合条件,而includes()则将这个条件直接限制为了一个具体的值。使用方法如下:

// includes 接收两个参数,第一个是要查找的值 src,第二个是开始查找的索引 index
// 如果第二个参数即索引为正,则从该索引处开始查找
// 如果第二个参数即索引为负,则从 arr.length + index 处开始查找
// 第二个参数的默认值为 0
let arr = [1, 2, 3, 4]
arr.includes(2) // true
arr.includes(2, 1) // true
arr.includes(2, -1) // false
arr.includes() // false

实现方法类似于some()的实现,不再赘述,直接开始:

Array.prototype.myIncludes = function (src, index = 0) {
let flag = false, // 返回值,默认返回 false
len = this.length
index = index >= 0 ? index : len + index // 判断索引
for(let i = index; i < len; i ++) {
if(this[i] === src) {
flag = true
break
}
}
return flag
}

十四丶indexOf

indexOf()方法返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1。

(未完待续)

文章作者: JaCo Wu
文章链接: https://jacokwu.cn/blog/2019/03/26/原-JS原生数组方法的用法及其实现(二)/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 JaCo Wu的博客