前言
尽管有时候遍历数组只须要 for
循环则足矣,然而如果 API 利用切当,往往能更大程度的进步代码的可读性,缩小心智累赘~
常见的数组 API
Array.prototype.some
性能
判断数组中是否至多有一个项通过了预设的条件,后果返回 boolean
。
参数
callback
:执行的回调函数,用于条件判断。thisArg
:执行函数的this
指针。
场景
判断数组 [1, 2, 3, 5, 6, 7]
中是否存在偶数
const target = [1, 2, 3, 5, 6, 7]
if (target.some(a => a % 2 === 0)) {// do something}
Polyfill
Array.prototype.some = function(fn, thisArg) {
// 异样解决
if (this == null) {throw new TypeError('Cannot read property of null or undefined.')
}
if (typeof fn !== 'function') {throw new TypeError(`${fn} must be a function.`)
}
// 须要用 Object 包装一次 this
const O = Object(this)
const len = O.length || 0
for (let i = 0; i < len; i++) {if (i in O) {if (fn.call(thisArg, O[i], i, O)) {return true}
}
}
return false
}
Array.prototype.every
性能
判断数组中是否全副项都通过了预设的条件,后果返回 boolean
。
参数
callback
:执行的回调函数,用于条件判断。thisArg
:执行函数的this
指针。
场景
判断数组 [1, 2, 3, 5, 6, 7]
是否每个数都是偶数。
const target = [1, 2, 3, 5, 6, 7]
if (target.every((num) => num % 2 === 0)) {// do something}
Polyfill
Array.prototype.every = function(fn, thisArg) {
// 异样解决
if (this == null) {throw TypeError('Cannot read property of null or undefined')
}
if (typeof fn !== 'function') {throw TypeError(`${fn} is not a function`)
}
// 从新包装一次 this
const O = Object(this)
const len = O.length || 0
for (let i = 0; i < len; i++) {if (i in O) {if (!fn.call(thisArg, O[i], i, O)) {return false}
}
}
return true
}
Array.prototype.slice
性能
浅拷贝数组,能够指定开始和完结下标来对数组某段做拷贝。如果不增加任何参数,那么会间接拷贝整个数组。
参数
begin
(可选参数): 从这个下标开始拷贝,如果为正数,则示意从倒数第begin
开始拷贝。end
(可选参数): 从这个下标完结拷贝,如果为正数,则示意从倒数第end
完结拷贝。
场景
拷贝数组 [1, 2, 3, 5, 6, 7]
到另外一个数组。
const target = [1, 2, 3, 5, 6, 7]
const temp = target.slice()
Polyfill
Array.prototype.slice = function(begin, end) {if (this == null) {throw new TypeError('cannot read property of null or undefined')
}
// 如果 end 没有传就默认截到数组开端
end = (typeof end !== 'undefined') ? end : this.length
const cloned = []
const len = this.length
let i = 0
// 解决下 begin 参数
let start = begin || 0
start = (start >= 0) ? start : Math.max(0, len + start)
let upTo = (typeof end == 'number') ? Math.min(end, len) : len
if (end < 0) {upTo = len + end}
// 计算 upTo 到 start 之间的差值
let size = upTo - start
// 如果 size > 0 就计算
// 再拷贝到 cloned 数组中
if (size > 0) {for (i = 0; i < size; i++) {cloned[i] = this[start + i]
}
}
return cloned
};
Array.prototype.reduce
性能
对数组中的每个元素执行一个由您提供的 reducer 函数,将其后果汇总为单个返回值。
参数
-
callback
- accumulator
- currValue
- index
- array(调用
reduce
的数组)
initValue
场景
计算数组 [1, 2, 3, 5, 6, 7]
的和。
const target = [1, 2, 3, 5, 6, 7]
const sum = target.reduce((prev, curr) => prev + curr)
Polyfill
Array.prototype.reduce = function(fn, initValue) {
// 异样判断
if (this == null) {throw new TypeError('Cannot read property of null or undefined')
}
if (typeof fn !== 'function') {throw new TypeError(`${fn} must be a function`)
}
const O = Object(this)
const len = O.length || 0
let i = 0
let k = 0
let accumulator = initValue
// 遍历并拿到后果
while (i < len) {if (i in O) {if (!accumulator) {accumulator = O[i]
} else {accumulator = fn.call(this, accumulator, O[i], i, O)
}
} else {k++}
i++
}
// 空数组异样判断
if (k >= len) {throw new TypeError('Reduce of empty array with no initial value')
}
return accumulator
}
Array.prototype.map
性能
创立一个新数组,其后果是该数组中的每个元素调用一次提供的函数后的返回值。
参数
-
callback
currentValue
index
array
thisArg
场景
将数组 [1, 2, 3, 5, 6, 7]
转化成对象数组,格局为 [{val: 1}, ...]
const target = [1, 2, 3, 5, 6, 7]
const objArr = target.map((num) => {
return {val: num}
})
Polyfill
Array.prototype.map = function(fn, thisArg) {
// 异样判断
if (this == null) {throw new TypeError('Cannot read property of null or undefined.')
}
if (typeof fn !== 'function') {throw new TypeError(`${fn} is not a function.`)
}
const O = Object(this)
const len = O.length || 0
const res = []
// 遍历并拿到后果
for (let i = 0; i < len; i++) {if (i in O) {res.push(fn.call(thisArg, O[i], i, O))
}
}
return res
}
总结
看完下面这些 Polyfill
之后,咱们能够找到一些法则,以便遇到没见过的 Polyfill
也能写出个大略:
- 对
this
指针和传入的回调函数做异样判断 - 对
this
用Object
从新包装一层 - 具体的逻辑解决,每个函数都不太一样
- 返回后果
参考资料
- MDN
搜寻「tony 老师的前端补习班」关注我的微信公众号,那么就能够第一工夫收到我的最新文章。