前言
虽然有时候遍历数组只需要 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
重新包装一层 - 具体的逻辑处理,每个函数都不太一样
- 返回结果
参考资料
搜索「tony老师的前端补习班」关注我的微信公众号,那么就可以第一时间收到我的最新文章。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。