JavaScript原生方法
简介
我们平时在写代码的时候会用到JavaScript自带的许多原生方法,如果我们不知道它们内部是怎么实现的,那么就会大大增加使用困惑。
本篇会带领我们搞懂原生方法使用的前提下,并且自己实现该方法。
1. JavaScript数组
1. forEach
原生
遍历数组
这是我们经常用到的遍历数组原生函数
let arr = [8, 1, 6, 7, 5, 9, 10]
arr.forEach((value,index,arr)=>{
console.log("当前值为",value); // 8,1,6,7,5,9,10
console.log("当前索引为",index); // 0,1,2,3,4,5,6
console.log("传进来的数组为",arr); // [8, 1, 6, 7, 5, 9, 10]
})
手写
Array.prototype.myforEach = function (callback) {
for (let i = 0; i < this.length; i++) {
callback(this[i], i, this)
}
}
他的内部是用for循环实现的,你可能会问那为什么不直接用for循环遍历而是要用forEach呢,因为方便啊!
2. map
原生
将返回值添加到新数组中并返回,新数组和原数组长度一致。
let arr = [9, 1, 6, 7, 5, 9, 10]
let newArr = arr.map((value, index, arr) => {
console.log("当前值为", value);
console.log("当前索引为", index);
console.log("传进来的数组为", arr);
return value * 10;
})
Console.log(newArr) // [90,10,60,70,50,90,100]
手写
Array.prototype.myMap = function (callback) {
const res = []
for (let i = 0; i < this.length; i++) {
// 不管真和假,全部push进新数组,所以才导致 '新数组和原数组长度一致'
res.push(callback(this[i], i, this))
}
return res
}
3. filter
原生
遍历数组,如果返回值为真,将当前元素添加到新数组
let arr = [9, 1, 6, 7, 5, 9, 10]
let newArr = arr.filter((value, index, arr) => {
console.log("当前值为", value);
console.log("当前索引为", index);
console.log("传进来的数组为", arr);
return value > 9;
})
console.log(newArr); // [10]
手写
Array.prototype.myFilter = function (callback) {
const res = []
for (let i = 0; i < this.length; i++) {
// &&:短路运算符,当第一个条件为false时后面的 res.push(this[i]) 不会运行
callback(this[i], i, this) && res.push(this[i])
}
return res
}
这里经常有很多人将map和filter函数认为功能一致,但是不是这样的,我们看它们内部代码就知道map是将返回值添加到新数组里。而filter是通过判断当前返回值是否为true,如果为true才添加当前值进新数组。
我教你们怎么分辨它们,filter单词本就有 '过滤器' 的含义,所以它是负责过滤不满足条件的元素,而过滤条件是你的返回值,记住,它只是过滤元素,而不改变原本的元素。如果你的数组为[1,2,3,4],你用filter返回的新数组中如果有值,那么值一定是[1,2,3,4]中存在的。
map单词有 '地图' 的含义,它只照着你的 '地图'(返回值)来重新push进新数组里,不管你给它的是任何东西。
4. every
原生
检测数组中的所有元素是否都满足指定条件,当有一个元素不符合要求时停止循环并返回false
let arr = [9, 1, 6, 7, 5, 9, 10]
let newArr = arr.every((value, index, arr) => {
console.log("当前值为", value);
console.log("当前索引为", index);
console.log("传进来的数组为", arr);
return value > 1; // 所有元素都需要大于1
})
console.log(newArr); // false
手写
Array.prototype.myEvery = function (callback) {
let flag = true
for (let i = 0; i < this.length; i++) {
flag = callback(this[i], i, this)
if (!flag) break;
}
return flag
}
5. some
原生
检测数组中的所有元素是否有一个元素满足指定条件,当有一个属性符合要求时停止循环并返回true
let arr = [9, 1, 6, 7, 5, 9, 10]
let newArr = arr.some((value, index, arr) => {
console.log("当前值为", value);
console.log("当前索引为", index);
console.log("传进来的数组为", arr);
return value = 9;
})
console.log(newArr); // true
手写
Array.prototype.mySome = function (callback) {
let flag = false
for (let i = 0; i < this.length; i++) {
flag = callback(this[i], i, this)
if (flag) break
}
return flag
}
这里又要分辨一下every和some的区别了。
every单词有 '每一个' 的含义,必须所有都满足条件才返回true,否则不讲道理就返回false
some单词有 '一些' 的含义,当有一个满足条件我就给你通过,如果你一个都不满足那我也没办法只能返回false
6. reduce
原生
可用于数组求和,它的索引是从1开始的。
// 第一回合:reduce函数如果没有初始值则为数组第一个值,goValue为数组第二个值
// 第二回合:value为上一回合返回的值,govalue为数组第三个值,以此类推。
let arr = [9, 2, 6, 7, 5, 9, 10]
let newArr = arr.reduce((value, goValue, index) => {
console.log("当前值为", value);
console.log("下一个值为", goValue);
console.log("当前索引为", index);
return value + goValue;
})
console.log(newArr); // 48
console.log(arr.reduce(fn..., 2)); // 50 初始值为2,那么第一回合vakue为2
手写
Array.prototype.myReduce = function (callback, ...args) {
let start = 0, pre
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
}
7. findIndex
原生
查找指定值的
索引位置,如果未找到返回-1
let arr = [9, 2, 6, 7, 5, 9, 10]
let newArr = arr.findIndex((value, index, arr) => {
console.log("当前值为", value);
console.log("当前索引为", index);
console.log("传进来的数组为", arr);
return value == 5;
})
console.log(newArr); // 4
手写
Array.prototype.myFindIndex = function (callback) {
for (let i = 0; i < this.length; i++) {
if (callback(this[i], i, this)) {
return i
}
}
return -1
}
8. find
原生
查找指定值的
值,如果未找到返回undefined
let arr = [9, 2, 6, 7, 5, 9, 10]
let newArr = arr.find((value, index, arr) => {
console.log("当前值为", value);
console.log("当前索引为", index);
console.log("传进来的数组为", arr);
return value == 5;
})
console.log(newArr); // 5
手写
Array.prototype.myFind = function (callback) {
for (let i = 0; i < this.length; i++) {
if (callback(this[i], i, this)) {
return this[i]
}
}
return undefined;
}
9. fill
原生
填充替换数组中的元素
let a = [1, 2, 3, 4, 5, 6]
let newA = a.fill("x",2,5) // [1, 2, 'x', 'x', 'x', 6]
// 第一个参数为要替换的值,第二个为开始位置的索引,第三个为到哪个元素结束,如果找不到该元素就替换到结尾
手写
Array.prototype.myFill = function (value, start = 0, end) {
end = end || this.length
for (let i = start; i < end; i++) {
this[i] = value
}
return this
}
10. includes
原生
检测数值是否包含某个元素,它和some不同点就是它可以检测NaN
let a = [1, 2, 3, 4, 5, 6, NaN]
let newA = a.includes(NaN,2) // true
// 第一个参数为要寻找的值,第二个值为从哪个索引位置开始查找,如果为负数就全局查找
手写
Array.prototype.myIncludes = function (value, start = 0) {
if (start < 0) start = this.length + start
const isNaN = Number.isNaN(value)
for (let i = start; i < this.length; i++) {
if (this[i] === value || Number.isNaN(this[i]) === isNaN) {
return true
}
}
return false
}
11. join
原生
将数组以指定分隔符分隔为字符串
let a = [1, 2, 3, 4, 5, 6, NaN]
let newA = a.join(",") // 1,2,3,4,5,6,NaN
// 分隔符如果省略,元素自动用逗号分隔
手写
Array.prototype.myJoin = function (s = ',') {
let str = ''
for (let i = 0; i < this.length; i++) {
str = i === 0 ? `${str}${this[i]}` : `${str}${s}${this[i]}`
}
return str
}
12. flat
原生
将多维数组拍平
let a = [1, 2, 3, [30, 40, [50, 60]], 4, 5, 6, NaN, [10, 20]]
let newA = a.flat(2) // [1, 2, 3, 30, 40, 50, 60, 4, 5, 6, NaN, 10, 20]
// 不传参数默认拍平一层
手写
Array.prototype.myFlat = function () {
let arr = this
while (arr.some(item => Array.isArray(item))) {
arr = [].concat(...arr)
}
return arr
}