JS 数组(检测)、原生方法、遍历方法、数组去重

510 阅读6分钟

如何判断一个变量是否为数组

错误的判断方法
  • typeof方法
var list = [1,2,3]
typeof list   // object

typeof会直接返回Object,不可以使用typeof检测

  • instanceof方法
var list = [1,2,3]
list instanceof Array  // true

这种方法并不可靠,原因是Array实质是一个引用,用instanceof方法都是利用和引用地址进行比较的方法来确定的,有局限性。

  • constructor方法
var list = [1,2,3]
list.constructor === Array   // true
正确的方法
  • 利用Object的toString方法(object.prototype.toString.call()方法) Object的原型对象上有一个toString方法,默认被所有对象继承,返回“【object type】”字符串。但此方法经常被原型链上的同名方法覆盖,需要通过
var list = [1,2,3]
Object.prototype.toString.call(list) // [object Array]
  • 利用ES6的Array.isArray()方法
var list = [1,2,3]
Array.isArray(list)  // true

数组的原生方法有哪些

增加
  • Array.prototype.push()在数组的末尾增加一个或多个元素,并返回数组的新长度。

image.png

  • Array.prototype.unshift()在数组的开头增加一个或多个元素,并返回数组的新长度。

image.png

删除
  • Array.prototype.pop()删除数组的最后一个元素,并返回这个元素。

image.png

  • Array.prototype.shift()删除数组的第一个元素,并返回这个元素。

image.png

修改
  • Array.prototype.splice()在任意的位置给数组添加、替换、删除任意个元素。

image.png

查找
  • Array.prototype.find()找到第一个满足测试函数的元素并返回那个元素的值,如果找不到,则返回undefined。

image.png

  • Array.prototype.findIndex()找到第一个满足测试函数的元素并返回那个元素的索引,如果找不到,则返回-1。

image.png

  • Array.prototype.indexOf()返回数组中第一个与指定值相等的元素的索引,如果找不到这样的元素,则返回-1。

image.png

image.png

image.png

  • Array.prototype.lastIndexOf()返回数组中最后一个与指定值相等的元素的索引,如果找不到这样的元素,则返回-1。

image.png

image.png

排序
  • Array.prototype.sort()对数组元素进行排序,并返回当前数组。

image.png 如果想按照其他标准进行排序,需要提供比较函数。

image.png

  • Array.prototype.reverse()颠倒数组中元素的排列顺序。

image.png

合并
  • Array.prototype.join()连接所有数组元素组成一个字符串

image.png

  • Array.prototype.concat()返回一个由当前数组和其它若干个数组或者若干个非数组值组合而成的新数组。

image.png

image.png

遍历
  • Array.prototype.forEach()为数组中的每个元素执行一次回调函数。

image.png

image.png

检测
  • Array.prototype.includes()判断当前数组是否包含某制定的值,如果是返回true,否则返回false.

image.png 从第6个索引位置查找: image.png

  • Array.prototype.every()如果数组中的每个元素都满足测试函数,则返回true,否则返回false。

image.png

image.png

  • Array.prototype.some()如果数组中至少有一个元素满足测试函数,则返回true,否则返回false。

image.png

image.png

过滤
  • Array.prototype.filter()将所有在过滤函数中返回true的数组元素放进一个新数组中并返回。

image.png

截取数组
  • Array.prototype.slice()抽取当前数组中的一段元素组合成一个新数组。

image.png

映射
  • Array.prototype.map()返回一个由回调函数的返回值组成的新数组。

image.png

数组遍历的方法

for循环
let arr = [1,2,3,4]
for(let j = 0,len=arr.length; j < len; j++) {
   console.log(arr[j]); // 1 2 3 4
}
forEach
 // 没有返回值
//  参数:value数组中的当前项, index当前项的索引, array原始数组;
//  数组中有几项,那么传递进去的匿名回调函数就需要执行几次;
let arr = [1,2,3,4]
arr.forEach((item,index,array)=>{
   console.log(index+':'+arr[index]);
})
// 执行结果
0:1
1:2
2:3
3:4
map

map的回调函数中支持return返回值; 并不影响原来的数组,只是相当于把原数组克隆一份,把克隆的这一份的数组中的对应项改变了。

var ary = [12,23,24,42,1];
var res = ary.map(function (item,index,ary ) {
    return item*10;
})
console.log(res);//-->[120,230,240,420,10];  原数组拷贝了一份,并进行了修改
console.log(ary);//-->[12,23,24,42,1];  原数组并未发生变化
filter遍历

不会改变原始数组,返回新数组

var arr = [
  { id: 1, value: 2 },
  { id: 2, value: 4 },
  { id: 2, value: 7 },
]
let newArr = arr.filter(item => item.value>2);
console.log(newArr ,arr )

for of 遍历

可以调用break、continue和return语句。

var myArray= [12,23,24,42,1];
for (var value of myArray) {
  console.log(value);// 12,23,24,42,1
}
every遍历

every()是对数组中的每一项运行给定函数,如果该函数对每一项返回true,则返回true。如果返回false,就退出遍历.

var arr = [ 1, 2, 3, 4, 5, 6 ];
  if(arr.every( function( item, index, array ){
       return item > 3;
  })){
       console.log("满足条件,每一个都大于3" );
   }else{
       console.log("不满足条件,不是每一个都大于3" );
   }
some遍历

some()是对数组中每一项运行指定函数,如果该函数对任一项满足条件,则返回true,就退出遍历;否则返回false。

var arr = [ 1, 2, 3, 4, 5, 6 ];
  if(arr.some( function( item, index, array ){
       return item > 3;
  })){
       console.log("");
   }else{
       console.log("不满足条件,没有大于3的" );
   }
reduce

reduce 为数组中的每一个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素,接受四个参数:初始值(或者上一次回调函数的返回值),当前元素值,当前索引,调用 reduce 的数组。

var total = [0,1,2,3,4].reduce((a, b)=>a + b); //10
console.log(total)
find

find()方法返回数组中符合测试函数条件的第一个元素。否则返回undefined

let name= [
   {
       name: '张三',
       gender: '男',
       age: 20
   },
   {
       name: '王小毛',
       gender: '男',
       age: 20
   },
   {
       name: '李四',
       gender: '男',
       age: 20
   }
];
function getStu(element){
  return element.name == '李四'
}
name.find(getStu)

forEach和map的区别

一、forEach():没有返回值

var array = [1,2,3,4,5,6];  
var res = array.forEach(function (item,index,input) {  
       input[index] = item*10;  
})  
console.log(res);//--> undefined;  
console.log(array);//--> 通过数组索引改变了原数组;[10,20,30,40,50,60]
  • 参数:value数组中的当前项,index当前项的索引,array原始数组;

  • 数组中有几项,那么传递进去的匿名回调函数就需要执行几次

  • 理论上这个方式是没有返回值的,只是遍历数组中的每一项, 不对原来数组进行修改,但是可以自己通过数组的索引来修改原来的数组

二、map():有返回值,可以return出来

var array = [10,34,57,43,76];  
var res = array.map(function (item,index,input) {  
       return item*10;
})  
console.log(res); // [100,340,570,430,760]
console.log(array); // 不变 [10,34,57,43,76]
  • 参数:value数组中的当前项,index当前项的索引,array原始数组

  • 区别:map的回调函数中支持return返回值,return的是啥,相当于把数组中的这一项变为啥(并不影响原来的数组,只是相当于把原数组克隆了一份,把克隆这一份的数组中的对应项改变了 )

for...in,for...of
  • 推荐在循环对象属性的时候,使用for...in,在遍历数组的时候的时候使用for...of

  • for...in循环出的是key,for...of循环出的是value

  • 注意,for...of是ES6新引入的特性。修复了ES5引入的for...in的不足

  • for...of不能循环普通的对象,需要通过和Object.keys()搭配使用

for(let index in aArray){
    console.log(`${aArray[index]}`);
}
for(var value of aArray){
    console.log(value);
}
map

map() 方法创建一个新的数组,其结果是该数组中的每个元素都调用一个提供的函数(callback)后返回的结果。

let newArray = arr.map(function 
    callback( currentValue[,index[, array]] ){
    // return element for newArray
}[, thisArg])

map接受两个参数,一个回掉函数callback,一个回掉函数this的值,其中回掉函数接受三个函数currentValue,index,array;

栗子:

["1","2","3"].map(parseInt)

['1', '2', '3'].map( (item,index) => {
       console.log( item,index )
       return parseInt( item,index )
 })
  
 /*
    打印的结果为:
    '1'     0    
    '2'     1
    '3'     2
 */
 
 /*
   返回值:
    parseInt( '1', 0 )    // 1
    parseInt( '2', 1 )    // NaN
    parseInt( '3', 2 )    // NaN    
 */

题目中的map只传入了回掉函数-parseInt,其次,parseInt只接受两个参数string,radix(基数)

let m = parseInt( string[, radix] );

string:要被解析的值。若参数不是字符串,则会被隐式转换成字符串( toString()方法 )。字符串开头的空白符将会被忽略。

radix:一个介于2和36之间的整数(不包含36),表示上述字符串的基数。默认为10。返回值:返回一个整数或者NaN(基数就是类似的进制数)(特别的:当radix为0时会当做默认10进制处理)。

parseInt(100,3)        // (1*3^2)+(0*3^1)+(0*3^0) = 9
 
parseInt(15,3)          // 会忽略比3大的数5,直接解析数字1,即(1*3^0) = 1
     
parseInt(6,3)            // 忽略比3大的数字6,解析空字符串,即 NaN
 
parseInt(250,3)        // 忽略比3大的数字5,且数字5后面的也会被忽略,2*3^0 = 2

如何将类数组的变量转化为数组

Array.from()方法

function f(){
   return Array.from(arguments);
}
f(1,2,3);  // [1,2,3]

数组去重

方法一:ES6 Set去重
let arr = [1,2,3,1,2]

function uniqueArray(arr){
    return Array.from(new Set(arr))
}

console.log(uniqueArray(arr)) // [1, 2, 3]

这种方法无法去掉“{}”空对象。

方法二:for循环+splice去重
let arr = [1,2,3,1,2]

function uniqueArray(arr){
for(let i = 0;i<arr.length;i++){
    for(let j = i+1;j<arr.length;j++){
        if(arr[j] === arr[i]){
            arr.splice(j,1);
            j--;
        }
    }
}
    return arr
}

console.log(uniqueArray(arr)) // [1, 2, 3]

双层循环,外层循环元素,内层循环时比较值。值相同时,则删去这个值。

方法三:indexOf去重
let arr = [1,2,3,1,2]

function uniqueArray(arr){
 if(!Array.isArray(arr)){
     return;
 }
 
 var array = []
 for(let value of arr){
     if(array.indexOf(value) === -1){
         array.push(value)
     }
 }
 return array;
}

console.log(uniqueArray(arr)) // [1,2,3]

新建一个空的结果数组,for 循环原数组,判断结果数组是否存在当前元素,如果有相同的值则跳过,不相同则push进数组。

方法四:利用sort()函数去重
let arr = [1,2,3,1,2]

function uniqueArray(arr){
 if(!Array.isArray(arr)){
     return;
 }
 
 arr = arr.sort()
 var array =[arr[0]]
 for(var i = 1;i <arr.length;i++){
     if(arr[i] !== arr[i-1]){
         array.push(arr[i])
     }
 }
 return array;
}

console.log(uniqueArray(arr))

利用sort()排序方法,然后根据排序后的结果进行遍历及相邻元素比对。

方法五:利用includes,includes检测数组是否有某个值。
let arr = [1,2,3,1,2]

function uniqueArray(arr){
    var array = []
    for(var i = 0;i<arr.length;i++){
        if(!array.includes(arr[i])){
            array.push(arr[i])
        }
    }
    return array;
}

console.log(uniqueArray(arr)) // [1,2,3]
方法六:利用filter+hasOwnProperty,hasOwnProperty 判断是否存在对象属性
let arr = [1,2,3,1,2]

function uniqueArray(arr){
    var obj = {}
    return arr.filter(function(item){
        return obj.hasOwnProperty(typeof item + item) ? false :
        (obj[typeof item + item] = true)
    })
    
}

console.log(uniqueArray(arr)) // [1,2,3]
方法七:利用filter+ indexOf
let arr = [1,2,3,1,2]

function uniqueArray(arr){
   
    return arr.filter(function(item,index,arr){ 
    // 当前元素,在原始数组中的第一个索引 == 当前索引值,否则返回当前元素
        return arr.indexOf(item,0) === index
    })
    
}

console.log(uniqueArray(arr)) // [1,2,3]
方法八:递归法
let arr = [1,2,3,1,2]

function uniqueArray(arr){

let array = arr
let len = array.length;
array.sort()
function loop(index){
    if(index >= 1){
        if(array[index] === array[index - 1]){
            array.splice(index,1)
        }
        loop(index-1);// 递归loop
    }
}
loop(len - 1)
return array;
    
}

console.log(uniqueArray(arr))
方法九:Map数据结构去重
let arr = [1,2,3,1,2]

function uniqueArray(arr){

let map = new Map()
let array = []; // 数组用于返回结果
for(let i = 0;i < arr.length; i++){
    if(map.has(arr[i])){ // 如果有该key值
        map.set(arr[i],true)
    }else {
        map.set(arr[i],false) // 如果没有该key值
        array.push(arr[i])
    }
}
return array;   
}

console.log(uniqueArray(arr)) // [1,2,3]

创建一个空Map数据结构,遍历需要去重的数组,把数组的每一个元素作为key存到Map中。由于Map中不会出现相同的key值,所以最终得到的就是去重后的结果。

方法十:reduce + includes
let arr = [1,2,3,1,2]

function unique(arr){
    return arr.reduce((prev,cur) => prev.includes(cur) ? prev : [...prev,cur],[]);
}
console.log(uniqueArray(arr))

多维数组转为一维数组

  • 利用Array.prototype.soString()方法
var list = [1,[2,[3]],4,[5]];
console.log(list.toString()); // 1,2,3,4,5
  • 利用Array.prototype.join()方法
var list = [1,[2,[3]],4,[5]];
console.log(list.toString()); // 1,2,3,4,5

*** 对上面的返回值加以修改为一个数组***

var list = [1,[2,[3]],4,[5]];
JSON.parse(`[${list.toString()}]`);//[1,2,3,4,5]
JSON.parse(`[${list.join()}]`); // [1,2,3,4,5]

如何克隆一个数组

  • 借用concat方法
var arr1 = [1,2,3]
var arr2 = arr1.concat()
  • 借用slice方法
var arr1 = [1,2,3]
var arr2 = arr1.slice(0);

找出Array中的最大元素

  • 利用Math的max方法
var list = [1,100,22,34]
Math.max.apply(null,list)
  • 利用Array的sort方法先排序再取值
var list = [1,22,1122,33]
list.sort((a,b)=>{return a-b;})