数组基本操作方法
以下方法均改变原数组,需要操作数组的 length 属性
Push
- 返回值:新数组的长度
- 思路:数组的长度等于
arguments[i]
Array.prototype.myPush = function () {
for (let i = 0; i < arguments.length; i++) {
this[this.length] = arguments[i];
}
return this.length;
};
Pop
- 返回值:删除的项(如果空数组,返回 undefined)
- 思路:让数组长度 -1
Array.prototype.myPop = function () {
return this.length==0?undefined:(this[this.length - 1],this.length--);
};
Shift
- 返回值:删除的项
- 思路:让数组前一个值
this[i]
等于后一个值this[i + 1]
,之后把数组长度 -1
Array.prototype.myShift = function () {
if (this.length == 0) {
return;
}
let del = this[0];
for (let i = 0; i < this.length; i++) {
this[i] = this[i + 1];
}
this.length--;
return del;
};
Unshift
- 返回值:新数组的长度
- 思路:让数组后一个值
this[i]
等于前 n(n=arguments.length
)个值this[i - arguments.length]
,之后把前 n 个值填为arguments[i]
Array.prototype.myUnshift = function () {
this.length += arguments.length;
for (let i = this.length - 1; i >= 0; i--) {
if (i >= arguments.length) {
this[i] = this[i - arguments.length];
} else {
this[i] = arguments[i];
}
}
return this.length;
};
- ES6 方法实现能简单一些。其实就是拼接数组,之后把拼接的数组一项一项赋值给原数组
Array.prototype.myUnshift = function (...arg) {
var newArr = [...arg, ...this];
for (let i = 0; i < newArr.length; i++) {
this[i] = newArr[i];
}
return this.length;
};
数组操作方法
以下方法除splice(改变原数组)均不改变原数组
splice(特殊)
因为 push 实现比较简单,这里用到了 push 方法,能简写一两行
-
返回值:删除的项(数组)
-
思路:按参数数量分别进行判定
- 参数小于等于1个,从 start 开始添加到新数组,并把添加那项删除(数组长度也减少)
- 参数大于1个,先进行删除(跟上一步相同)再把数组分成三份,左边+中间被替换的项+右边,合并数组
注意:
- 第一个参数为负数:如果转换为正数,大于数组长度,直接转换为0;小于等于数组长度,需加上数组长度
- 第二个参数:如果小于0,直接转换为0
- 第三个参数起:要添加的项
Array.prototype.mySplice = function (start, del) {
let arr = [];
if (start < 0) {
start = -start > this.length ? 0 : this.length + start;
}
if (arguments.length <= 1) {
for (let i = start; i < this.length; i++) {
arr.push(this[i]);
}
this.length = start;
} else {
del = del < 0 ? 0 : del;
// 删除数组这一步
for (let i = 0; i < del; i++) {
arr.push(this[start + i]);
this[start + i] = this[start + i + del];
}
this.length -= del;
let lArr = [];
for (let i = 0; i < start; i++) {
lArr.push(this[i]);
}
for (let i = 0; i < arguments.length - 2; i++) {
lArr.push(arguments[i + 2]);
}
for (let i = start; i < this.length; i++) {
lArr.push(this[i]);
}
for (let i = 0; i < lArr.length; i++) {
this[i] = lArr[i];
}
}
return arr;
};
- 删除数组那一步,我第一时间想到的是冒泡(把删除项一次一次冒到最后一位),最后出来的代码是下面这样(非常麻烦)
let that = del;
for (let i = that; i > 0; i++) {
if (that <= 0) {
break;
}
for (let j = start; j < this.length - 1; j++) {
[this[j], this[j + 1]] = [this[j + 1], this[j]];
}
arr.push(this[this.length - 1]);
this.length--;
that--;
}
- 大可不必这样,把删除项的下一位(不删除)往前挪一个一个覆盖要删除的项即可
for (let i = 0; i < del; i++) {
arr.push(this[start + i]);
this[start + i] = this[start + i + del];
}
this.length -= del;
concat
- 返回值:拼接后的新数组
- 思路:如果参数是数组需遍历后一个一个添加到新数组
Array.prototype.myConcat = function () {
let arr = [];
for (let i = 0; i < this.length; i++) {
arr[i] = this[i];
}
for (let i = 0; i < arguments.length; i++) {
const el = arguments[i];
if (Array.isArray(el)) {
for (let i = 0; i < el.length; i++) {
arr[arr.length] = el[i];
}
} else {
arr[arr.length] = el;
}
}
return arr;
};
slice
- 返回值:复制后的新数组
- 思路:如果传参是负数索引,需对其长度进行判定。如果大于数组长度,将其改为0;小于数组长度,将其改为
arr.length+(负数索引)
Array.prototype.mySlice = function (start = 0, end = this.length) {
var arr = [];
if (start < 0) {
start = -start > this.length ? 0 : this.length + start;
}
if (end < 0) {
end = -end > this.length ? 0 : this.length + end;
}
for (let i = start; i < end; i++) {
arr.push(this[i]);
}
return arr;
};
flat
- 返回值:扁平后的新数组
- 思路:递归(下面实现没有加上可以指定递归深度的参数,类似
arr.flat(Infinity)
)
Array.prototype.myFlat = function () {
let arr = [];
fn(this);
function fn(ary) {
for (let i = 0; i < ary.length; i++) {
const item = ary[i];
if (Array.isArray(item)) {
fn(item);
} else {
arr.push(item);
}
}
}
return arr;
};
Array.prototype.myFlat = function () {
return this.toString().split(",").map((item) => Number(item));
};
数组重排方法
reverse
- 返回值:倒序后的数组
- 思路:第n个数和倒数第n个数两两对换
Array.prototype.myReverse = function () {
for (let i = 0, j = this.length - 1; j > i; i++, j--) {
var temp = this[i];
this[i] = this[j];
this[j] = temp;
}
return this;
};
sort
- 返回值:排序后的数组
- 思路:不传参的时候,两两比较 String(xxx) 的值;传参的时候判断
callBack(a-b)
是否大于 0 即可
Array.prototype.mySort = function (callBack) {
if (this.length <= 1) {
return this;
}
if (typeof callBack === "function") {
for (let i = 0; i < this.length - 1; i++) {
for (let j = 0; j < this.length - 1 - i; j++) {
if (callBack(this[j], this[j + 1]) > 0) {
[this[j], this[j + 1]] = [this[j + 1], this[j]];
}
}
}
} else if (typeof callBack === "undefined") {
for (let i = 0; i < this.length - 1; i++) {
for (let j = 0; j < this.length - 1 - i; j++) {
if (String(this[j]) > String(this[j + 1])) {
[this[j], this[j + 1]] = [this[j + 1], this[j]];
}
}
}
} else {
return "参数异常";
}
return this;
};
数组位置方法
以下方法均不改变原数组
indexOf
- 返回值:索引/-1
- 思路:遍历数组,第二个参数是从哪个索引开始。如果不传参,从头查到尾部
Array.prototype.myIndexOf = function (val, index = 0) {
if (index < 0) {
index = -index > this.length ? 0 : index + this.length;
}
for (let i = index; i < this.length; i++) {
if (this[i] === val) {
return i;
}
}
return -1;
};
lastIndexOf
- 返回值:索引/-1
- 思路:遍历数组,第二个参数是到哪个索引结束(从0开始到这个索引结束)。如果不传参,从头查到尾部
Array.prototype.myLastIndexOf = function (val, index = this.length) {
if (index < 0) {
index = -index >= this.length ? 0 : index + this.length;
}
for (let i = index; i >= 0; i--) {
if (this[i] === val) {
return i;
}
}
return -1;
};
includes
- 返回值:true/false
- 思路:遍历数组
Array.prototype.myIncludes = function (val) {
for (let i = 0; i < this.length; i++) {
if (this[i] === val) {
return true;
}
}
return false;
};
数组迭代方法
以下方法均不改变原数组
forEach
回调函数内部 this 一般指向 window
- 返回值:undefined
- 思路:遍历数组
Array.prototype.myForEach = function (callBack) {
for (let i = 0; i < this.length; i++) {
let index = i, item = this[i];
callBack(item, index);
}
};
map
- 返回值:映射后的新数组
- 思路:遍历数组,把数组每以项经过运算后赋值给新数组
Array.prototype.myMap = function (callBack) {
let arr = [];
for (let i = 0; i < this.length; i++) {
let index = i, item = this[i];
arr[i] = callBack(item, index);
}
return arr;
};
reduce
- 返回值:函数累计处理的结果
- 思路:initial 返回值在数组的每次迭代中被记住,最后成为最终的结果值
Array.prototype.myReduce = function (callBack, initial) {
if (typeof callBack !== "function") throw new TypeError("callBack must be function");
let i = 0;
if (typeof initial === "undefined") {
initial = this[0];
i = 1;
}
for (; i < this.length; i++) {
initial = callBack(initial, this[i], i)
}
return initial;
};
find
- 返回值:找到就返回符合的元素,没有返回 undefined
- 思路:遍历数组
Array.prototype.myFind = function (callBack) {
for (let i = 0; i < this.length; i++) {
if (callBack(this[i], i)) return this[i]
}
}
every
- 返回值:只要有一个不符合返回false,如果都符合返回 true
- 思路:遍历数组,一假即假
Array.prototype.myEvery = function (callBack) {
for (let i = 0; i < this.length; i++) {
if (!callBack(this[i], i)) return false
}
return true
}
some
- 返回值:只要有一个符合就返回 true,如果都符合返回 false
- 思路:遍历数组,一真即真
Array.prototype.mySome = function (callBack) {
for (let i = 0; i < this.length; i++) {
if (callBack(this[i], i)) return true
}
return false
}
filter
- 返回值:一个新数组,数组里面是符合条件的所有元素
- 思路:遍历数组
Array.prototype.myFilter = function (callBack) {
if (!Array.isArray(this) || !this.length || typeof callback !== 'function') {
return []
}
let arr = [];
for (let i = 0; i < this.length; i++) {
if (!callBack(this[i], i)) {
arr.push(this[i]);
}
}
return arr
}