工作笔记--js数组去重、数组对象去重,找出数组中的最大值,判断数据类型,对象合并

950 阅读10分钟

数组去重,即从一个数组中移除所有重复的元素,确保每个元素只出现一次,是这一类问题的核心。

使用原生 JavaScript 方法

1. filter() 方法配合 indexOf()

const uniqueArray = array.filter((item, index, self) => {
  return self.indexOf(item) === index;
});

该方法利用 filter() 遍历数组,对于每个元素,通过 indexOf() 查找其在原数组中的第一个索引。如果当前元素的索引与正在遍历的索引相同,说明这是该元素在数组中的首次出现,保留该元素;否则,忽略该元素。

2. reduce() 方法

const uniqueArray = array.reduce((acc, current) => {
  return acc.includes(current) ? acc : [...acc, current];
}, []);

这里使用 reduce() 函数将数组累积到一个新的数组(acc)中。在每次迭代中,检查当前元素是否已存在于累积数组中。若不存在,则将其添加至累积数组;否则,跳过该元素。

利用 ES6 新特性

1. 使用扩展运算符与解构赋值

const uniqueArray = [...new Set(array)];

这种方法简洁高效,利用 ES6 的 Set 数据结构自动去除重复元素的特性,再通过扩展运算符将 Set 转换回数组。Set 是一种特殊的集合,不允许重复元素存在,因此插入过程会自动过滤重复项。

2. 利用 Map 数据结构

const uniqueArray = Array.from(new Map(array.map(item => [item, item])).values());

尽管不如直接使用 Set 直观,但此方法同样有效。它首先将数组映射为键值对相同的 Map,由于 Map 键的唯一性,重复的数组元素会被自动忽略。然后通过 Array.from() 和 Map.values() 将 Map 的值(即无重复元素)转换回数组。

双重循环与哈希表

1. 双重循环

const uniqueArray = [];
for (let i = 0; i < array.length; i++) {
  let isDuplicate = false;
  for (let j = 0; j < i; j++) {
    if (array[i] === array[j]) {
      isDuplicate = true;
      break;
    }
  }
  if (!isDuplicate) {
    uniqueArray.push(array[i]);
  }
}

这种方法最直观也最基础,通过外层循环遍历数组,内层循环检查当前元素是否与之前的所有元素重复。如果没有重复,则将其添加到结果数组中。虽然理解简单,但时间复杂度较高,不适用于大型数据集。

2. 利用对象作为哈希表

const uniqueArray = [];
const hashTable = {};
for (let i = 0; i < array.length; i++) {
  const item = array[i];
  if (!hashTable[item]) {
    uniqueArray.push(item);
    hashTable[item] = true;
  }
}

这种方法利用对象作为哈希表,以数组元素作为键。在遍历过程中,若元素尚未作为对象的键存在,则添加到结果数组并将其设置为哈希表的键。由于对象属性查找的时间复杂度接近 O(1),这种方法在处理大量数据时比双重循环更为高效。

性能比较与优化策略

1. 性能比较

  • filter() + indexOf():线性时间复杂度 O(n^2),适合小型数据集。
  • reduce():线性时间复杂度 O(n^2),适合小型数据集。
  • 扩展运算符与 Set:近乎线性时间复杂度 O(n),非常高效,适合各种规模的数据集。
  • Map:近乎线性时间复杂度 O(n),非常高效,适合各种规模的数据集。
  • 双重循环:平方时间复杂度 O(n^2),效率低,仅适用于极小数据集。
  • 哈希表:近乎线性时间复杂度 O(n),高效,适合各种规模的数据集。

2. 优化策略

  • 选择合适的方法:根据数据规模和项目需求,优先考虑使用 SetMap 或哈希表方法,它们具有更高的时间效率。
  • 预处理数据:如果可能,提前对数据进行排序或转换,简化去重逻辑,提高效率。
  • 懒加载与分批处理:对于超大规模数据,可采用懒加载或分批处理策略,避免一次性加载全部数据导致的性能瓶颈。
  • 使用 Web Worker:对于计算密集型的去重操作,可以考虑使用 Web Worker 进行多线程处理,避免阻塞主线程影响用户体验。

数组对象去重的方式,先看看数组对象的形式:

// 原数据是这样的                   // 去重后数据是这样的
[{                                [{
  "goodsId": "1",                    "goodsId": "1",
  "quota": 12,                       "quota": 12,
  "skuId": "1"                       "skuId": "1"
},                                 },
{                                  {
  "goodsId": "2",                    "goodsId": "2",
  "quota": 12,                       "quota": 12,
  "skuId": "2"                       "skuId": "2"
},                                 }]
{
  "goodsId": "1",
  "quota": 12,
  "skuId": "1"
}]

1.使用filter和Map

代码简洁,好用,4行代码搞定,平均耗费时间最短,五星推荐

  1. 法一:
    // 原数据是这样的                   // 去重后数据是这样的
    const arr = [{                              //  [{
      "goodsId": "1",                 //   "goodsId": "1",
      "quota": 12,                      // "quota": 12,
      "skuId": "1"                       //"skuId": "1"
    },                                 //},
    {                                  //{
      "goodsId": "2",                    //"goodsId": "2",
      "quota": 12,                       //"quota": 12,
      "skuId": "2"                       //"skuId": "2"
    },                                 //}]
    {
      "goodsId": "1",
      "quota": 12,
      "skuId": "1"
    }]

    function uniqueFunc (arr) {
      let m = new Map();
      return arr.filter((ele) => !m.has(ele.skuId) && m.set(ele.skuId, ""));
    }
    let arr2 = uniqueFunc(arr)
    console.log('aee', arr2);
  1. 法二
   // 方法一:
    let map = new Map();
    for (let item of arr) {
      if (!map.has(item.skuId)) {
        map.set(item.skuId, item);
      };
    };
    console.log('map', map);
    arr3 = [...map.values()];
    console.log(arr3)

  1. 法三
  let nArr = arr.filter((currentValue, currentIndex, selfArr) => {
      return selfArr.findIndex(x => x.skuId === currentValue.skuId) === currentIndex
    });
    console.log('nArr', nArr);

2.使用reduce

代码稍多,平均耗费时间和第一不分伯仲,四星推荐

function uniqueFunc2(arr, uniId){
  let hash = {}
  return arr.reduce((accum,item) => {
    hash[item[uniId]] ? '' : hash[item[uniId]] = true && accum.push(item)
    return accum
  },[])
}
3.使用for循环

耗费时间较一二稍多,但是耗费时间平均,三星推荐


function uniqueFunc3(arr, uniId){
  let obj = {}
  let tempArr = []
  for(var i = 0; i<arr.length; i++){
    if(!obj[arr[i][uniId]]){
      tempArr.push(arr[i])
      obj[arr[i][uniId]] = true
    }
  }
  return tempArr
}

js获取数组中的最大值的9种方法

每种方法的工作原理和用法。以下是每种方法的详细说明:

1.方法1:Math.max()apply()

  • 使用Math.max()函数和apply()方法来找到数组中的最大值。

  • apply()方法将Math.max()函数应用于数组,它将数组的元素作为参数传递给Math.max()函数。

  • 返回数组中的最大值。

const arr = [1, 3, 5, 2, 4];
const max = Math.max.apply(``null``, arr);
console.log(max); ``// 输出:5`

2.方法2:for循环遍历数组

  • 使用for循环遍历数组,从第一个元素开始比较,找到最大值。
  • 初始化一个变量max为数组的第一个元素。
  • 从数组的第二个元素开始,依次与max比较,如果当前元素大于max,则更新max为当前元素。
  • 返回数组中的最大值。
const arr = [1, 3, 5, 2, 4];
let max = arr[0];
for (let i = 1; i < arr.length; i++) {
  if (arr[i] > max) {
    max = arr[i];
  }
}
console.log(max); // 输出:5

3.方法3:reduce()方法

  • 使用reduce()方法来迭代数组,并在每次迭代时找到最大值。
  • 初始值设置为Number.MIN_SAFE_INTEGER,确保数组中的任何值都可以成为最大值。
  • 在每次迭代时,使用Math.max()函数来比较当前元素和累加器的值,返回较大的值作为下一次迭代的累加器。
  • 返回数组中的最大值。
const arr = [1, 3, 5, 2, 4];
const max = arr.reduce((acc, cur) => Math.max(acc, cur), Number.MIN_SAFE_INTEGER);
`console.log(max); ``// 输出:5`

4.方法4:sort()方法

  • 使用sort()方法对数组进行排序。
  • 默认情况下,sort()方法按照字符串顺序对元素进行排序。
  • 通过提供一个比较函数,可以确保按照数字顺序对元素进行排序。
  • 将数组的最后一个元素作为最大值返回。
const arr = [1, 3, 5, 2, 4];
arr.sort((a, b) => a - b);
const max = arr[arr.length - 1];
`console.log(max); ``// 输出:5`

5.方法5:spread语法和Math.max()函数

  • 使用展开运算符(Spread Operator)将数组的元素作为参数传递给Math.max()函数。
  • 返回数组中的最大值。
const arr = [1, 3, 5, 2, 4];
const max = Math.max(...arr);
console.log(max); // 输出:5

6.方法6:ES6的解构赋值和sort()方法

  • 使用展开运算符(Spread Operator)将数组的元素作为参数传递给sort()方法进行排序。
  • 使用解构赋值将排序后的数组的第一个元素赋值给变量max。
  • 返回数组中的最大值。
const arr = [1, 3, 5, 2, 4];
const [max] = [...arr].sort((a, b) => b - a);
`console.log(max); ``// 输出:5`

7.方法7:ES6的解构赋值和reduce()方法

  • 使用reduce()方法迭代数组,并在每次迭代时找到最大值。
  • 初始值设置为Number.MIN_SAFE_INTEGER,确保数组中的任何值都可以成为最大值。
  • 在每次迭代时,使用解构赋值将当前元素和累加器的值分别赋值给变量cur和max。
  • 如果cur大于max,则更新max为cur。
  • 返回数组中的最大值。
const arr = [1, 3, 5, 2, 4];
const [max] = arr.reduce(([max], cur) => 
cur > max ? [cur] : [max],
[Number.MIN_SAFE_INTEGER]);
console.log(max); // 输出:5

8.方法8:Math.max()函数和展开运算符(Spread Operator)

  • 使用展开运算符(Spread Operator)将数组的元素作为参数传递给Math.max()函数。
  • 返回数组中的最大值。
const arr = [1, 3, 5, 2, 4];
const max = Math.max(...arr);
`console.log(max); ``// 输出:5`

判断数据类型

常见的判断js数据类型的方法有如下几种

1.最常见的判断方法:typeof

2.已知对象类型: instanceof

3.对象原型链判断方法: prototype 通用但很繁琐

4.根据对象的构造器constructor进行判断

5.jQuery方法: jquery.type()

6.严格运算符: ===

一.typeof

其中typeof返回的类型都是字符串形式,需注意!!!!!

  • 只能识别基础类型和引用类型 注意:null、 NaN、 document.all 的判断
alert(typeof "helloworld")    ------------------>"string"     
alert(typeof 123)             ------------------>"number"
alert(typeof [1,2,3])         ------------------>"object"
alert(typeof new Function())  ------------------>"function"
alert(typeof new Date())      ------------------>"object"
alert(typeof new RegExp())    ------------------>"object"
alert(typeof Symbol())        ------------------>"symbol"
alert(typeof true)            ------------------>"true"
alert(typeof null)            ------------------>"object"
alert(typeof undefined)       ------------------>"undefined"
alert(typeof 'undefined')     ------------------>"string"

二.instance of

注意:instanceof 后面一定要是对象类型,并且大小写不能错,该方法适合一些条件选择或分支。

[1,2,3] instanceof Array                -------->true
new Date() instanceof Date              -------->true
new Function() instanceof Function      -------->true
new Function() instanceof function      -------->false
null instanceof Object                  -------->false

三.对象原型链判断方法: Object.prototype.toString.call()

适用于所有类型的判断检测,注意区分大小写. toString方法,在Object原型上返回数据格式

 console.log(Object.prototype.toString.call("123"))           -------->[object String]
 console.log(Object.prototype.toString.call(123))             -------->[object Number]
 console.log(Object.prototype.toString.call(true))            -------->[object Boolean]
 console.log(Object.prototype.toString.call([1, 2, 3]))       -------->[object Array]
 console.log(Object.prototype.toString.call(null))            -------->[object Null]
 console.log(Object.prototype.toString.call(undefined))       -------->[object Undefined]
 console.log(Object.prototype.toString.call({name: 'Hello'})) -------->[object Object]
 console.log(Object.prototype.toString.call(function () {}))  -------->[object Function]
 console.log(Object.prototype.toString.call(new Date()))      -------->[object Date]
 console.log(Object.prototype.toString.call(/\d/))            -------->[object RegExp]
 console.log(Object.prototype.toString.call(Symbol()))        -------->[object Symbol]

四.根据对象的constructor进行判断

constructor 判断方法跟instanceof相似,但是constructor检测Object与instanceof不一样,constructor还可以处理基本数据类型的检测,不仅仅是对象类型

  • 语法:obj instanceof Type
  • 功能:判断 obj 是不是 Type 类的实例,只可用来判断引用数据
  • 实现思路: Type 的原型对象是否是 obj 的原型链上的某个对象
  • 注意:右操作数必须是函数或者 class
   //注意当出现继承的时候,使用constructor会出现问题
    function A() {};
 
    function B() {};
    A.prototype = new B(); //A继承自B
    console.log(A.constructor === B)  -------->false
    var C = new A();
    //现在开始判断C是否跟A的构造器一样
    console.log(C.constructor === B)  -------->true
    console.log(C.constructor === A)  -------->false 
    //解决这种情况,通常是手动调整对象的constructor指向
    C.constructor = A; //将自己的类赋值给对象的constructor属性
    console.log(C.constructor === A);  -------->true
    console.log(C.constructor === B);  -------->false

五.有局限的判断:严格运算符===

通常===出现在我们的条件判断中,比如判断一个变量是否为空,变量是否为数据等,示例如下

var a = null;
typeof a //object
a === null  //true
 
/*扩展补充*/
 
//判断一个非数组变量是否为空
if(typeof a != 'undefined' && a ){}
 
//判断一个数组变量是否为空
if (typeof a != “undefined” && a && a.length > 0) {}

总结

方法基础数据类型引用类型注意事项
typeof×NaN、object、document.all
constructor√ 部分可以被改写
instanceof×多窗口,右边构造函数或者class
isPrototypeof×小心 null 和 undefined
toString小心内置原型
Symbol.toString Tag×识别自定义对象
等比较特殊对象

数组里面的对象合并

 let obj = [
   { name1: '张三', age1: "12" },
   { name2: '李四', age2: "14" },
   { name3: '王五', age3: "30" }
 ]

 let newObj = {} // 新建一个对象

 obj.forEach((item) => {
   newObj = { ...newObj, ...item }  // 要把自己放进去
 })

 console.log(newObj) // { name1: "张三", age1: "12", name2: "李四", age2: "14", name3: "王五", age3: "30" }

ps:工作中用过的一些知识点,自己记录的笔记和整理来网络上的资源 ,方便以后复习使用。