-
Notifications
You must be signed in to change notification settings - Fork 8
Description
实现数组方法(下)
所有数组方法的实现均忽略参数校验、边界条件判断,主要关注核心逻辑的实现。
部分数组方法会基于Array.prototype.reduce方法来实现,关于reduce方法的讲解及实现详见彻底搞懂数组reduce方法
Array.prototype.push()
push()方法将一个或多个元素添加到数组的末尾,并返回该数组的新长度。
push()方法可用于类数组对象,需要注意的是length不存在或无法转为数值时,将被设置为0,并从索引0开始添加元素。
Array.prototype._push = function(...args) {
const len = Number(this.length) || 0
this.length = len
for (arg of args) {
this[this.length++] = arg
}
return this.length
}Array.prototype.reduceRight()
MDN - Array.prototype.reduceRight()
reduceRight()方法接受一个函数作为累加器(accumulator)和数组的每个值(从右到左)将其减少为单个值。
之前已实现过reduce()方法,详情见文章开头,我们使用其来实现reduceRight()方法。
Array.prototype._reduceRight = function(callback) {
const len = this.length
if (arguments.length >= 2) {
return [...this].reverse().reduce((acc, cur, i) => {
return callback(acc, cur, len - 1 - i, this)
}, arguments[1])
} else {
return [...this].reverse().reduce((acc, cur, i) => {
return callback(acc, cur, len - 1 - i, this)
})
}
}Array.prototype.reverse()
MDN - Array.prototype.reverse()
reverse()方法将数组中元素的位置颠倒,并返回该数组。数组的第一个元素会变成最后一个,数组的最后一个元素变成第一个。该方法会改变原数组。
通过交换数组左右对应位置的值实现,这样只用迭代Math.floor(this.length / 2)次。
Array.prototype._reverse = function() {
const len = this.length
for (let i = 0; i < Math.floor(len / 2); i++) {
const correspondIndex = len - 1 - i;
[this[i], this[correspondIndex]] = [this[correspondIndex], this[i]]
}
return this
}Array.prototype.shift()
shift()方法从数组中删除第一个元素,并返回该元素的值。此方法更改数组的长度。
Array.prototype._shift = function() {
if (!this.length) return undefined
// 记录第一项并删除
const valToDel = this[0]
delete this[0]
// 之后项依次左移
for (let i = 0; i < this.length - 1; i++) {
this[i] = this[i + 1]
}
// 删除最后一项
delete this[this.length - 1]
// 修正数组长度
this.length--
return valToDel
}Array.prototype.slice()
slice()方法返回一个新的数组对象,这一对象是一个由 begin 和 end 决定的原数组的浅拷贝(包括 begin,不包括end)。原始数组不会被改变。
Array.prototype._slice = function(beginIndex = 0, endIndex = this.length) {
const begin = beginIndex < 0 ?
Math.max(this.length + beginIndex, 0) :
Math.min(beginIndex, this.length)
const end = endIndex < 0 ?
Math.max(this.length + endIndex, 0) :
Math.min(endIndex, this.length)
const count = end - begin
if (count <= 0) return []
const result = new Array(count)
for (let i = 0; i < count; i++) {
if (i in this) {
result[i] = this[begin + i]
}
}
return result
}Array.prototype.some()
some()方法测试数组中是不是至少有1个元素通过了被提供的函数测试。它返回的是一个Boolean类型的值。
some()方法具有短路特性,且会跳过数组稀疏项。
Array.prototype._some = function(callback, thisArg) {
for (let i = 0; i < this.length; i++) {
if (i in this && callback.call(thisArg, this[i], i, this)) {
return true
}
}
return false
}Array.prototype.splice()
MDN - Array.prototype.splice()
splice()方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。
Array.prototype._splice = function(startIndex, deleteCount = this.length - startIndex, ...items) {
const len = this.length
const start = startIndex < 0 ?
Math.max(len + startIndex, 0) :
Math.min(len, startIndex)
const realDeleteCount = deleteCount <= 0 ?
0 :
Math.min(len - start, deleteCount)
const deleteVals = this.slice(start, start + realDeleteCount)
const right = [...items, ...this.slice(start + realDeleteCount)]
for (let i = 0; i < right.length; i++) {
this[start + i] = right[i]
}
// 修正length属性,自动删除多余项
this.length = start + right.length
return deleteVals
}Array.prototype.unshift()
MDN - Array.prototype.unshift()
unshift()方法将一个或多个元素添加到数组的开头,并返回该数组的新长度(该方法修改原有数组)。
Array.prototype._unshift = function(...items) {
const addCount = items.length
if (addCount === 0) return this.length
this.length += items.length
for (let i = this.length - 1; i >= 0; i--) {
if (i >= addCount) {
this[i] = this[i - addCount]
} else {
this[i] = items[i]
}
}
return this.length
}Array.prototype.values()
MDN - Array.prototype.values()
values()方法返回一个新的 Array Iterator 对象,该对象包含数组每个索引的值,实现方法与keys()、entries()相似。
Array.prototype._values = function(...items) {
function *gen() {
for (let i = 0; i < this.length; i++) {
yield this[i]
}
}
return gen.call(this)
}