栈、队列方法
-
栈:一个门
-
push 从尾加,pop从尾删。
-
push(): 可以接受任意类型的参数,将他们逐个添加到数组的末尾,并返回数组的长度
-
pop():从数组的末尾移除最后一项,减少数组的length值,返回移除的项
var arr = [1,2] var len = arr.push(3,4,5) console.log(arr) //[ 1, 2, 3, 4, 5 ] console.log(len) //5 var delItem = arr.pop() console.log(arr) //[ 1, 2, 3, 4 ] console.log(delItem) //5
-
-
队列:两个门
- shift 从头删,unshift从头加
- shift() :移除数组中的第一个项,返回移除的项,同时将数组的长度减1
- unshift():在数组的前端添加任意个项,并返回数组的长度
排序方法
-
reverse(): 反转数组项的顺序,返回反转后的数组
-
sort(): 返回排序后的数组 默认不带参数时:该方法会先调用每个数组项的toString()方法,然后按照字符序列排列ASIIC码。
以下代码是在node交互命令行中运行的
> arr3 = [ 4,1,5,,undefined,null,undefined,{}]
> [ 4, 1, 5, <1 empty item>, undefined, null, undefined, {} ]
>arr3.sort()
>[ 1, 4, 5, {}, null, undefined, undefined, <1 empty item> ]
ps、null,undefined没有toString方法
自定义排序:该方法可以接受一个比较函数作为参数,该比较函数返回结果,根据自己需要,修改if中的条件 ;返回负数,两个位置不交换;返回正数,两个数位置交换
var arr2 = [3,7,2,9,8]
arr2.sort(compare)
function compare(a,b){
if(a>b){ //a<b升序 a>b降序
return -1; //负数不交换
}
return 1;//正数交换
}
console.log(arr2)
//compare可精简为以下
function compare(a,b){
return a-b; //降序
//return b-a; //升序
}
- 可以自己封装万能比较函数
截取方法
-
concat():数组拼接,先创建当前数组的一个副本,然后将接收到的参数添加到这个副本的末尾,返回副本,不改变原数组。【如果是参数是数组展开放进去,如果是单个其他的直接放到末尾】
> var arr = [1,2,3] undefined > arr.concat(7,8,9) [ 1, 2, 3, 7, 8, 9 ] >
-
slice():数组切割,
slice(参数1 [,参数2])
参数1:返回项的起始位置,参数2:结束位置,不包含结束位置。若只有一个参数,表示从该参数指定位置开始,截取到当前数组末尾的所有项。返回切割的元素组成的数组,不改变原数组。不传参数,还可用于数组的深复制
var arr0 = [1,2,3] var arr1 = arr0; arr1[0] = 0 arr //[0,2,3] arr1会更改arr //--- var arr2 = arr0.slice() arr2[0] = 2 arr //不会因为arr2改变而变化
-
splice():返回的是删除的元素组成的数组,改变原数组
splice(参数1[,参数2,参数3,参数4])
参数1:开始位置;参数2:删除的项数;参数3,添加元素一个或多个
删除
> var arr = [1,2,3] undefined > arr.splice(1) [ 2, 3 ] > arr [ 1 ] >只传一个参数,默认删到最后和slice传一个参数的效果一样 > var arr = [32,7,3,26,0,1] > undefined > arr.splice(1,3) > [ 7, 3, 26 ] > arr > [ 32, 0, 1 ] >
添加/插入:第二个参数为0
>var arr = [32,7,3,26,0,1] >undefined >arr.splice(1,0,1,2) >[] >arr [ 32, 1, 2, 7, 3, 26, 0, 1 ] >
替换:将1,2替换成了3,4;【接着上面的code继续】
[ 32, 1, 2, 7, 3, 26, 0, 1 ] > arr.splice(1,2,3,4) [ 1, 2 ] > arr [ 32, 3, 4, 7, 3, 26, 0, 1 ] >
索引方法
-
indexOf(参数1[,参数2]):从数组开头向后查找,使用全等操作符,找不到该元素返回-1,找到了返回所在的下标
参数1:要查找的项,参数2:索引开始的位置,默认为0
-
lastIndexOf:除了是从数组末尾向前查找,其余和indexOf一样
迭代方法
参数:第一个参数是每一项上运行的函数,第二个参数是用于更改函数内部的this指向,一般不写
- every 所有元素符合条件,返回true 相当于&&
- some 有元素符合条件 返回true 相当于||
- filter 过滤满足条件的元素,返回被过滤的元素组成的数组
- map 返回每次函数调用的结果组成的数组
- forEach 对数组中的每一元素运行给定的函数 没有返回值 常用来遍历元素
是否更改原数组
改:push pop shift unshift reverse sort splice
不改:concat slice every some forEach map filter-->迭代方法
数组的方法可以链式调用
遍历数组的常用方法
有:for 、forEach、for of、for in(不推荐)
var array = ["xjm","sjak"]
for(var i =0;i<array.length;i++){
console.log(array[i])//xjm sjak
}
for(value of array){
console.log(value) //xjm sjak
}
for(key in array){
console.log(array[key]) //xjm sjak
}
array.forEach(function(item,index,arr){
console.log(item) //xjm sjak
})
虽然for… in 、 for… of 都能够变历数组,但是两者还是有很大区别的
主要区别在于他们的迭代方式:
- for-in循环出来的式key,for-of循环出来的是value
- for-in是ES5标准,for-of是ES6标准,兼容性可能存在问题
- 推荐for-in遍历对象,for-of遍历数组
for...in 循环除了遍历数组元素外,还会遍历自定义属性。所以万一给一个数组加了个属性也会被遍历出来, 故不推荐for-in遍历数组。(数组本质是对象,是可以自定义添加属性的)。 for-of则不会,for...of只可以循环可迭代的可迭代属性,不可迭代属性在循环中被忽略了
未赋值的值是不会在foreach循环迭代的,但是手动赋值为undefined的元素是会被列出的
自己实现数组的一系列方法
在学习了数组的一系列方法后,脑海中始终有很多的好奇和疑惑,想知道他们是如何实现的,如果换做是我,我又该如何实现这些功能呢 ?
目前实现:reverse,pop,push,shift,unshift,concat,every,some,slice,map,filter, forEach。
【尽管代码不够最优,但我先记录一下自己最初的想法,往后会多多学习并修正】
总结:重点关注,参数,返回值,是否更改原来的数组;基于关注的点,把要实现的功能理一下,然后用代码表达出来。
1,参数不确定,借助arguments对象
2,是否更改原数组,涉及到this的更改问题--如何实现数组的深复制or浅复制
改原数组:push pop shift unshift reverse sort splice
不改原数组:concat slice every some forEach map filter
3,return 返回值;
返回更改后数组的长度:push pop shift unshift 【注意push,unshift接收一个或多个参数的情况】
返回更改后的数组: reverse sort
返回操作后的数组:concat slice splice(返回删除元素组成的数组)map filter【注意concat可接收数组作为参数,和多个罗列的数值作为参数时的处理情况】
返回布尔值:some,every
没有返回值:forEach
参考code:
var array = [1, 2, 3,{}];
/*思路:
var arr0 = []
arr0.length = arr.length;
arr0[0]=arr[arr.length-1]
arr0[1]=arr[arr.length-2]
arr0[2]=arr[arr.length-3]
arr0[i]=arr[arr.length-i-1]
for(var i=0;i<arr.length;i++){
arr0[i]=arr[arr.length-i-1]
}
console.log(arr0)
*/
/**------myReverse */
//this 谁调用就是谁
Array.prototype.myReverse = function() {
var arr = [];
for (var i = 0; i < this.length; i++) {
arr[i] = this[this.length - i - 1];
}
//加了,就是更改原数组
for(var j=0;j<this.length;j++){
this[j] = arr[j]
}
return this;
};
array.myReverse();
/*----myPop*/
Array.prototype.myPop = function(){
this.length -= 1;
return this.length;
}
array.myPop()
/*----myPush*/
//array[len+0]=arguments[0]
// array[len+1]=arguments[1]
// array[len+2]=arguments[2]
Array.prototype.myPush = function() {
// var nums = arguments.length;//实参个数,arguments是类数组对象
for (key in arguments) {
this[this.length] = arguments[key]; //this.length随着我们给this[this.length]赋值,长度会增加
}
return this.length;
};
array.myPush(7, 8, 9);
/**------myShift */
/**shift从头部删除
* arr[0] = arr[1]
* arr[1] = arr[2]
*/
Array.prototype.myShift = function(){
for(var i=0;i<this.length;i++){
this[i] = this[i+1]
}
this.length--;//删掉最后一个undefined
return this.length;
}
array.myShift()
/**---myUnshift---在头部加*/
/**嫁入3个参数的话 arguments.length=3
* arr[arguments.length]=arr[0]
* arr[arguments.length+1]=arr[1]
* arr[arguments.length+2]=arr[2]
* arr[0]=arguments[0]
* arr[1]=arguments[1]
* arr[2]=arguments[2]
*/
var arr2=[1,2,3]
Array.prototype.myUnshift=function(){
// console.log(arguments) for in 、for都可遍历它
for(let i=0;i<arguments.length;i++){
this[arguments.length+i]=this[i]
this[i]=arguments[i]
}
return this.length;
}
arr2.myUnshift(4,5,6)
/**----myConcat */
var array = [1,1,1,1]
/**
* 不改变原数组
* 如果参数是数组,需要拆开放到末尾
* 如果参数是其他,直接放进末尾
* 返回副本
*/
Array.prototype.myConcat=function() {
var temp = [];
for(let i =0;i<this.length;i++){
temp[i] = this[i]
}
// console.log(arguments.length)
// console.log(Array.isArray(arguments[0]))
if(arguments.length==1&&(Array.isArray(arguments[0]))){
//如果只有一个是数组的参数
var paramsArr = arguments[0];
for(var i =0;i<paramsArr.length;i++){
temp.push(paramsArr[i])
}
}else{
//是其他散列的参数,类似1,2,3,就从arguments中遍历出来
for(key in arguments){
temp.push(arguments[key])
}
}
return temp;
}
// var result = array.myConcat('hello','h')
var result = array.myConcat([6,7])
console.log(result,array)
/**--------myEvery---- */
Array.prototype.myEvery =function(func,funcThis){
//this==>arr
for(var i=0;i<this.length;i++){
var result = func.call(funcThis,this[i],i,this)
if(!result){
break;
}
}
return result;
}
/**------mySome---- */
Array.prototype.mySome = function(func,funcThis) {
//第二个参数是用于更改函数内部的this指向,一般不写
for(var i=0;i<this.length;i++){
var result = func.call(funcThis,this[i],i,this);
if(result){
break;
}
}
return result;
}
var result = array.mySome(function(item,index,arr){
// console.log(item,index,arr) 对应上面在call中传递的参数
return item>5;
});
console.log(result) //false
/**------myMap---*/
Array.prototype.myMap = function(func, funcThis) {
var temp = [];
// console.log(this)
for (var i = 0; i < this.length; i++) {
funcThis ? temp.push(func.call(funcThis, this[i], i, this)):
temp.push(func(this[i], i, this));
}
return temp;
};
console.log(
array.myMap(function(item) {
return item * 2; //注意要return
})
);
var array = [1, 2, 3, 4, 5, 6, 7];
/**------myFilter---*/
Array.prototype.myFilter = function(func, funcThis) {
var temp = [];
// console.log(this)
for (var i = 0; i < this.length; i++) {
var result = func.call(funcThis, this[i], i, this);
if(result){
temp.push(this[i]);
}
}
return temp;
};
console.log(
array.myFilter(function(item) {
return item<4; //注意要写return
})
);
/**------myForEach---*/
Array.prototype.myForEach = function(func, funcThis) {
for (var i = 0; i < this.length; i++) {
func.call(funcThis, this[i], i, this);
}
};
array.myForEach(function(item) {
console.log(item); //forEach没有返回值,用来遍历数组,不用写return
})
封装mySlice时this问题
var array = [1, 2, 3,4,5,6,7];
/**------mySlice 不更改原数组*/
//接收0个,一个或两个参数
/**
* 0个 可实现数组的深复制【即单纯复制一份数组里的值出去,不与原数组有其他瓜葛】
* 1个 表示从该参数的指定位置开始,截取到当前数组的末尾所有项
* 2个 表示从指定位置开始到结束位置,不包含结束的
* 还需要注意有参时参数为负数的情况
* */
Array.prototype.mySlice = function() {
switch (arguments.length) {
case 0:
var temp = [];
for (let i = 0; i < this.length; i++) {
temp.push(this[i]);
}
return temp;
case 1:
// console.log(arguments[0])
arguments[0]=arguments[0] > 0 ? arguments[0]: this.length+arguments[0];
var temp = [];
for (let i = arguments[0]; i < this.length; i++) {
temp.push(this[i]);
}
return temp;
case 2:
arguments[0]=arguments[0] > 0 ? arguments[0]: this.length+arguments[0];
arguments[1]=arguments[1] > 0 ? arguments[1]: this.length+arguments[1];
var temp = [];
for (let i = arguments[0]; i < arguments[1]; i++) {
temp.push(this[i]);
}
return temp;
}
};
console.log(array.mySlice(-6,2));
console.log(array.mySlice(-1));
console.log(array.mySlice(-1,-2));
console.log(array.mySlice(-1,2));
-
代码优化,提取一些重复的code,进行封装!
-
还可以为了保证代码的健壮性,对传入的参数做一些错误处理
-
后续有想法的话根据情况写测试函数
Array.prototype.mySlice = function() {
switch (arguments.length) {
case 0:
// return te(); 不能这样用,因为这样this指向的时全局对象
return te.call(this);
case 1:
return te.call(this, arguments[0]);
case 2:
return te.call(this, arguments[0], arguments[1]);
}
};
/*te是我瞎取的,习惯不好,不要学*/
function te(params1, params2) {
// console.log(this) //this-->global 搞了半天undefined,原来是this指向问题
if (params1 || params2) {
params1 = params1 > 0 ? params1 : this.length + params1;
params2 = params2 > 0 ? params2 : this.length + params2;
}
var temp = [];
for (let i = params1 || 0; i < (params2 || this.length); i++) {
temp.push(this[i]);
}
return temp;
}
总之往代码更优雅和高效的方向进击!
送一张图:数组我们能赢!
