写在前面
因为有一次面试碰到了问有没有用过数组所有的内置方法?
、是否清楚所有内置方法的参数和使用?
当时并没有能全部答出来,所以决定从头理一篇所有的数组内置方法,并且自己实现一遍。主要是知识梳理,读者们也能从头梳理一遍。下面的方法尽量会全部自己实现,实在有困难的会google,然后注明出处。
concat
用于连接数组,但是不会改变数组,会返回一个连接后的结果数组
参数:可以是数组也可以是非数组
例子?
let a = [1, 2, 3]
let b = [4,5]
let c = [6,7,8,9]
a.concat(b, c) // [1,2,3,4,5,6,7,8,9]
简单实现
Array.prototype.concat2 = function (...arrays) {
let copy = this.slice(0) // 不用深度拷贝,因为原concat也没有深度拷贝
for (let i = 0; i < arrays.length; i++) {
const item = arrays[i]
if (!Array.isArray(item)) { // 不是数组直接push进copy
copy.push(item)
} else { // 数组的话递归concat进行连接
for (let j = 0; j < item.length; j++) {
copy = copy.concat2(item[j])
}
}
}
return copy
}
时间复杂度: 大概是O(n)
copyWithin
用于拷贝数组的元素到原数组的另一个指定位置,会改变原数组。IE 11 及更早版本不支持 copyWithin() 方法
参数 | 描述 | target:Number | 拷贝的目标位置(必须) | start:Number | 需要拷贝元素的开始位置(非必须,默认是0) | end:Number | 需要拷贝元素的结束位置(非必须,默认是length) |
---|
例子?
let a = [1,2,3,4,5,6]
a.copyWithin(2, 0, 1) // [1,2,1,4,5,6]
简单实现
Array.prototype.copyWithin2 = function (target, start, end) {
start = start || 0
end = end || this.length
const copy = []
for (let i = start; i < end; i++) {
copy.push(this[i])
}
const len = this.length > copy.length ? copy.length : this.length // 判断需要遍历赋值的最长长度
for (let i = 0, j = target; i < len; i++, j++) {
if (j >= this.length) {
break
}
this[j] = copy[i]
}
return this
}
entries
返回数组的可迭代对象
,不会修改源数组
可迭代对象
:这里推荐看阮一峰老师的Iterator 和 for...of 循环
例子?
let a = ['123', '456', '789']
let b = a.entries()
b.next() // {value: [0, '123'], done: false}
for (let v of b) {
console.log(v)
}
// [1, '456']
// [2, '789']
简单实现
Array.prototype.entries2 = function () {
return this[Symbol.iterator]()
}
Array.prototype[Symbol.iterator] = function () {
var nextIndex = 0;
return {
next: function() {
return nextIndex < this.length ?
{value: this[nextIndex++], done: false} :
{value: undefined, done: true};
}
}
}
every
会遍历每个元素是否满足用户给出的回调函数,是返回true,否返回false,并且不会继续检查。
不会对空数组检查,不会改变原数组
例子?
var ages = [32, 33, 16, 40];
function checkAdult(age) {
return age >= 18;
}
ages.every(checkAdult);// false
实现
Array.prototype.every2 = function (fn) {
if (this.length > 0) {
for (let i = 0; i < this.length; i++) {
if (!fn(this[i])) {
return false
}
}
}
return true
}
fill
用一个特定的值替换指定位置的数组元素,改变原数组。
参数:
参数 | 描述 | value | 必需。填充的值。 | start | 可选。开始填充位置。 | end | 可选。停止填充位置 (默认为 array.length) |
---|
例子?
var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.fill("Runoob", 2, 4); // Banana,Orange,Runoob,Runoob
实现
Array.prototype.fill2 = function (v, start = 0, end) {
end = end || this.length
for (let i = start; i < end; i++) {
this[i] = v
}
return this
}
filter
返回满足回调函数的元素数组,不会改变原数组
例子?
var ages = [32, 33, 16, 40];
function checkAdult(age) {
return age >= 18;
}
ages.filter(checkAdult);// [32, 33, 40]
实现
Array.prototype.filter2 = function (fn, ctx) {
ctx = ctx || this
const res = []
for (let i = 0; i < this.length; i++) {
if (fn.apply(ctx, [this[i], i, this])) {
res.push(this[i])
}
}
return res
}
find
返回满足回调函数的第一个值
不改变原数组,都不满足返回undefined
例子?
var ages = [3, 10, 18, 20];
function checkAdult(age) {
return age >= 18;
}
ages.find(checkAdult); // 18
实现
Array.prototype.find2 = function (fn, ctx) {
ctx = ctx || this
for (let i = 0; i < this.length; i++) {
if (fn.apply(ctx, [this[i], i, this])) {
return this[i]
}
}
return
}
findIndex
返回满足回调函数的第一个值的位置下标
不满足返回-1
不会改变原数组
例子?
var ages = [3, 10, 18, 20];
function checkAdult(age) {
return age >= 18;
}
ages.find(checkAdult); // 2
实现
Array.prototype.findIndex = function (fn, ctx) {
ctx = ctx || this
for (let i = 0; i < this.length; i++) {
if (fn.apply(ctx, [this[i], i, this])) {
return i
}
}
return -1
}
forEach()
数组每个元素都执行一次回调函数。不会修改原数组。但是当元素为引用类型时,会修改。
例子?
const b = [{v: 65}]
b.forEach(v => v.v += 1)
//b [{v: 66}]
实现
Array.prototype.forEach2 = function (fn, ctx = window) {
for (let i = 0; i < this.length; i++) {
fn.apply(ctx, [this[i], i, this])
}
}
from()
通过拥有 length 属性的对象或可迭代的对象来返回一个数组。(他有第二个参数,是个function,和map是一样的)
例子?
let a = {0: 'demo', 1: 'demo2', length: 2}
let b = Array.from(a)
console.log(b) //=>['demo', 'demo2']
实现
Array.from2 = function (data, mapFun = function (item) {return item}) {
let res = []
if (data.length) {
for (let i = 0; i < data.length; i++) {
res[i] = mapFun(data[i]) || null
}
} else if (typeof data[Symbol.iterator] === 'function') {
data.forEach((item) => {
res.push(mapFun(item))
})
}
return res
}
includes()
判断一个数组是否包含一个指定的值,包括NaN也能判断出来为true。
例子?
const a = [1,2,3,NaN]
a.includes(NaN) // true
实现
Array.prototype.includes2 = function (el, fromIndex = 0) {
if (typeof el === 'object') {
return false
}
if (fromIndex < 0) {
fromIndex = this.length + fromIndex
}
for (let i = fromIndex; i < this.length; i++) {
if (el.toString() === 'NaN') {
if (this[i].toString() === el.toString()) {
return true
}
} else {
if (this[i] === el) {
return true
}
}
}
return false
}
总结
这是第一篇,因为内置方法太多,剩下的放在第二篇,还在写哦...
作者只是自己瞎写写,肯定会有很多地方实现的不好,欢迎来指正哦
如果有什么不足或错误的地方,欢迎读者评论和留言
当然,要是本文对你有所帮助,欢迎点赞和转发,谢谢?
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!