「回顾2022,展望2023,我正在参与2022年终总结征文大赛活动」
1、前言
在我们conding中,我们都用过数组这个数据结构,我们除了使用了数组自带的增删改查方法,还会使用带数组身上各类的API方法,下面我就来介绍数组身上的各类api方法。
2、迭代属性的API方法
2.1 Array.every()
1. evrry()原理:
every()
方法接受一个回调函数作为参数,它是检查数组中的所有元素是否都通过了我们的限制条件,every()
方法对数组中存在的每个元素都会去执行一次:
- 如果找到函数返回 false 值的数组元素,
every()
返回 false,并且不检查剩余的元素 - 如果没有出现 false,
every()
返回 true every()
不改变原始数组
2. evrry()方法的手写实现:
const singer = [
{ name: '111', num: 20 },
{ name: '222', num: 25 },
{ name: '333', num: 19 },
{ name: '444', num: 10 },
{ name: '555', num: 0 },
]
Array.prototype.my_every = function(callback) {
for(let i = 0 ; i < this.length; i++) {
if(! callback(this[i],i,this) ){
return false
}
}
return true
}
const newSinger = singer.my_every((item, index, arr) => {
return item.num > 10 // singer[4].num < 10
})
console.log(newSinger); //false
2.2 Array.some()
1.some()原理
some()
方法也接受一个回调函数作为参数,与every()
相反,它是检查数组中的任何元素是否通过我们的限制条件,some()
方法对数组中存在的每个元素执行一次函数:
- 如果找到函数返回真值的数组元素,some() 返回ture,并且不检查剩余的元素
- 否则返回 false
some()
不改变原始数组。
2.some()方法的手写实现
const singer = [
{ name: '111', num: 20 },
{ name: '222', num: 25 },
{ name: '333', num: 19 },
{ name: '444', num: 10 },
{ name: '555', num: 0 },
]
Array.prototype.my_some = function(callback) {
for (let i = 0; i < this.length; i++) {
if (callback(this[i], i, this)) {
return true
}
}
return false
}
const newSinger = singer.my_some((item, index, arr) => {
return item.num > 20 // singer[1].num > 20
})
console.log(newSinger); // true
2.3 Array.map()
1.map()原理
map()
方法接收三个参数,分别为 item
(值)、index
(下标)、arr
(原数组),它使用为每个数组元素调用函数的结果创建新数组, 且函数一定要有return
,并不会改变原始数组。
2.map()方法的手写实现
const singer = [
{ name: '111', num: 20 },
{ name: '222', num: 25 },
{ name: '333', num: 19 },
{ name: '444', num: 10 },
{ name: '555', num: 0 },
]
Array.prototype.my_map = function(callback) {
const res = []
for (let i = 0; i < this.length; i++) {
res.push(callback(this[i], i, this))
}
return res
}
const newSinger = singer.my_map((item, index, arr) => {
return item.num > 20
})
console.log(newSinger); // [ false, true, false, false, false ]
2.4 Array.reduce()
1.reduce()原理
reduce()
方法接受两个参数,第一个参数是一个回调函数,这个回调函数接受四个参数,分别为pre
(上次函数的执行结果)、next
(值)、index
(下标)、arr
(原数组),第二个参数为第一次执行回调函数时pre
的初始值。
如果我们没有给第二个参数,则pre
为数组的第一个值,next
为数组的第二个值。reduce()
方法也不会改变原始数组。一般我们会使用reduce
方法实现数组的累加。
2.reduce()方法的手写实现
const singer = [
{ name: '111', num: 20 },
{ name: '222', num: 25 },
{ name: '333', num: 19 },
{ name: '444', num: 10 },
{ name: '555', num: 1 },
]
Array.prototype.my_reduce = function(callback, ...args) {
let pre, start = 0
if (args.length) {
pre = args[0]
} else {
pre = this[0]
start = 1
}
for (let i = start; i < this.length; i++) {
pre = callback(pre, this[i], i, this)
}
return pre
}
const newSinger = singer.my_reduce((pre, next, index, arr) => {
console.log(pre);//0 20 45 64 74
return pre + next.num
}, 0)
console.log(newSinger); // 75
2.5 Array.filter()
1.filter()原理
filter()
方法接收三个参数,分别为item
、index
、arr
,他创建了一个新的数组,其中填充了所有满足我们的限制条件的元素。filter()
也不会改变原始数组。
2.filter()方法的手写实现
const singer = [
{ name: '111', num: 20 },
{ name: '222', num: 25 },
{ name: '333', num: 19 },
{ name: '444', num: 10 },
{ name: '555', num: 0 },
]
Array.prototype.my_filter = function(callback) {
const res = []
for (let i = 0; i < this.length; i++) {
callback(this[i], i, this) && res.push(this[i])
}
return res
}
const newSinger = singer.filter((item, index, arr) => {
return item.num > 15
})
console.log(newSinger);
// [
// { name: '111', num: 20 },
// { name: '222', num: 25 },
// { name: '333', num: 19 }
// ]
2.6 Array.forEach()
1.forEach()原理
forEach()
方法一个回调函数作为参数,forEach()
方法按顺序为数组中的每个元素调用一次函数。
2.forEach()方法的手写实现
const singer = [
{ name: '111', num: 20 },
{ name: '222', num: 25 },
{ name: '333', num: 19 },
{ name: '444', num: 10 },
{ name: '555', num: 0 },
]
Array.prototype.my_forEach = function(callback) {
for (let i = 0; i < this.length; i++) {
callback(this[i], i, this)
}
}
singer.my_forEach((item, index, arr) => {
console.log(item, index);
})
// { name: '111', num: 20 } 0
// { name: '222', num: 25 } 1
// { name: '333', num: 19 } 2
// { name: '444', num: 10 } 3
// { name: '555', num: 0 } 4
3、查找属性的API方法
3.1 Array.find()
1.find()原理
find()
方法接收三个参数,分别为 val
(你要查找元素)、start
(开始查找的位置)、end
(结束的查找的位置),它返回数组中第一个通过限制的的元素的值。find()
方法对数组中存在的每个元素执行一次函数:
- 如果找到函数返回 true 值的数组元素,则 find() 返回该数组元素的值(并且不检查剩余值)
- 否则返回 undefined
find()
不会改变原始数组。
2.find()方法的手写实现
const singer = [
{ name: '111', num: 20 },
{ name: '222', num: 25 },
{ name: '333', num: 19 },
{ name: '444', num: 10 },
{ name: '555', num: 0 },
]
Array.prototype.my_find = function(callback) {
for (let i = 0; i < this.length; i++) {
if (callback(this[i], i, this)) {
return this[i]
}
}
return undefined
}
const res = singer.my_find((item, index, arr) => {
return item.num > 20
})
console.log(res); // { name: '222', num: 25 }
3.2 Array.findIndex()
1.findIndex()原理
findIndex()
方法与find()
方法原理相同,如果找到了返回对应下标值,否则返回-1
2.findIndex()方法的手写实现
const singer = [
{ name: '111', num: 20 },
{ name: '222', num: 25 },
{ name: '333', num: 19 },
{ name: '444', num: 10 },
{ name: '555', num: 0 },
]
Array.prototype.my_findIndex = function(callback) {
for (let i = 0; i < this.length; i++) {
if (callback(this[i], i, this)) {
return i
}
}
return -1
}
const res = singer.findIndex((item, index, arr) => {
return item.num > 30
})
console.log(res); // -1
4、其他的好用API方法
4.1 Array.include()
1.includes()原理
includes()
方法接收两个参数,第一个参数为数组是否包含的元素,第二个参数为从数组某个位置开始向后查找,如果第二个个参数为负数,则从负数加上数组长度的位置开始。如果数组包含元素,则此方法返回 true
,否则返回 false
。且该方法区分大小写。
使用includes()
方法时,我们要考虑当我们第一个参数为NaN
时,由于NaN != NaN
,所以在我们手写实现时,我们将这种情况考虑进去
2.includes()方法的手写实现
let obj = { name: '111', num: 25 }
const singer = [
{ name: '222', num: 20 },
obj,
{ name: '333', num: 19 },
{ name: '444', num: 10 },
{ name: '555', num: 0 },
]
const nums = [1, 2, 3, 4, 5, NaN]
Array.prototype.my_includes = function(val, start = 0) {
if (start < 0) start = this.length + start
const isNaN = Number.isNaN(val)
for (let i = start; i < this.length; i++) {
if (this[i] === val || (isNaN && Number.isNaN(this[i]))) { // NaN === NaN
return true
}
}
return false
}
const res = nums.my_includes(NaN, 0)
console.log(res); // true
4.2 Array.join()
1.join()原理
join()
方法将数组作为字符串返回。元素将由指定的分隔符分隔。默认分隔符是逗号 ,
。join()
方法不会改变原始数组。
2.join()方法的手写实现
const arr = [1, 2, 3, 4, 'hello']
Array.prototype.my_join = function(s = ',') {
let str = ''
for (let i = 0; i < this.length; i++) {
if (i === this.length - 1) {
str += this[i]
} else {
str += this[i] + s
}
// str += i === this.length - 1 ? this[i] : this[i] + s // 简洁版
}
return str
}
const str = arr.my_join()
console.log(str);
4.3 Array.flat()
1.flat()原理
flat()
方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。其接收一个参数默认值为1,表示需要深度遍历几次,超出数组维度则指挥遍历数组维度-1次,使其成为以为数组
2.flat()方法的手写实现
const arr = [ 1, 2, [3, 4, [5]], 6, {a: 7} ]
Array.prototype.myflat = function(num = 1) {
let newArr = this
let i = 0
while (newArr.some(item => Array.isArray(item)) && i < num) {
newArr = [].concat(...newArr)
i++
}
return newArr
}
const newArr = arr.myflat(4)
console.log(newArr); // [ 1, 2, 3, 4, 5, 6, { a: 7 } ]
4.4 Array.splice()
1.splice()原理
splice()
方法可以接收任意个参数,它的第一个参数为切割数组的起始位置(start),第二个参数为我们需要切割的长度(length),而后面的参数则为我们需要添加到原数组上的值。splice会改变原来的数组。在我们手写splice()
方法时,我们要注意以下几点:
- splice方法是先切割数组,再向其添加我们的想要向原数组的值
- splice方法会改变原数组,同时也会返回出一个新数组
- 当我们传进来的第一个参数为复数时,我们需要从(start+数组长度)的位置开始切割
- 当我们切割的长度大于原数组长度的最大值时,我们要改变新数组的长度,去除新数组后面的
undefined
值
2.splice()方法的手写实现
const singer = [
{ name: '111', num: 20 },
{ name: '222', num: 25 },
{ name: '333', num: 19 },
{ name: '444', num: 10 },
{ name: '555', num: 0 },
]
Array.prototype.my_splice = function (start, length, ...args) {
const result = [], targetArr = []; // 新数组 原数组
// 判断第一个参数是否小于零
if (start < 0) {
start = this.length + start
}
// 生成新数组同时将原数组剩余的值和要添加的值给到 targetArr
for (let i = 0; i < this.length; i++) {
if (i === start) {
for (let j = start; j < start + length; j++) {
result.push(this[j]);
i = j;
}
targetArr.push(...args);
if (!length) { targetArr.push(this[i]); }
} else {
targetArr.push(this[i]);
}
}
// 给原数组赋值
for (let i = 0; i < targetArr.length; i++) {
this[i] = targetArr[i]
}
// 去除新数组上的undefined
if (start + length > this.length) {
if (start === 0) {
result.length = this.length
} else {
result.length = this.length - 1 - start
}
}
this.length = targetArr.length
return result;
}
const arr = singer.my_splice(-2, 10, 'hello', 'world', '123')
console.log(singer);
// [
// { name: '111', num: 20 },
// { name: '222', num: 25 },
// { name: '333', num: 19 },
// 'hello',
// 'world',
// 'laoli'
// ]
console.log(arr);
// [ { name: '444', num: 10 }, { name: '555', num: 0 } ]
4.5 Array.fill()
1.fill()原理
fill()
方法接受三个参数,分别是分别为 val
(你要填充元素)、start
(开始查找的位置)、end
(结束的查找的位置),它是向数组中填充指定的元素。可以指定开始和结束填充的位置。如果未指定,则将填充所有元素。fill()
会覆盖原数组。要注意的一点是:当我们填充一个引用类型的数据时,当我们改变了该引用类型的值时,数组的值也会改变
2.fill()方法的手写实现
let obj = { name: '666', num: 12}
let singer = [
{ name: '111', num: 20 },
{ name: '222', num: 25 },
{ name: '333', num: 19 },
{ name: '444', num: 10 },
{ name: '555', num: 0 },
]
Array.prototype.my_fill = function(val, start = 0, end) {
end = end || this.length
for (let i = start; i < end; i++) {
this[i] = val
}
return this
}
singer.my_fill(obj, 0, 1)
console.log(singer[0]); //{ name: '666', num: 12 }
obj.num = 13
console.log(singer[0]); // { name: '666', num: 12 }
5、结语
学习阶段,欢迎指教,码字不易,点个赞呗。