前言
尽管有时候遍历数组只须要 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老师的前端补习班」关注我的微信公众号,那么就能够第一工夫收到我的最新文章。