JS中数组/对象操作集合

999 阅读3分钟

相关知识点

  • 数组去重
  • 数组截断
  • 过滤掉数组中的 falsy
  • 获取数组的最后一项
  • 清空数组
  • 使用 ... 运算符合并对象或数组中的对象
  • 有条件的添加对象属性
  • 解构原始数据
  • 动态更改对象的 key
  • 判断对象的数据类型
  • in 关键字的使用

数去去重

方案一(不推荐)

创建一个新数组,然后遍历旧数组,每次检查当前元素是否在新数组中,如果不存在,则加入,否则相反。

let arr = [1, 2, 1, 1, 1, 2, 3, 3, 3, 2];
let newArr = [];
for (let i = 0; i < arr.length; i++) {
  let item = arr[i];
  if (!newArr.includes(item)) {
    newArr.push(item);
  }
}
console.log(newArr); // [1, 2, 3]

方案二(不推荐)

每拿出一项数据,就与当前数组其他数据作对比,相同的数据进行删除,依次遍历所有数据。

let arr = [1, 2, 1, 1, 1, 2, 3, 3, 3, 2];
for (let i = 0; i < arr.length; i++) {
  var item = arr[i];
  for (let j = i + 1; j < arr.length; j++) {
    var compare = arr[j];
    if (compare === item) {
      arr.splice(j, 1); 
      // 数组塌陷问题:J 后边每一项索引都提前了一位,下次要比较应该还是 j 这个索引
      j--;
    }
  }
}
console.log(arr); // [1, 2, 3]

上方代码存在一个问题,就是数组塌陷。当我们使用 splice 方法删除的时候,通常将后边的数据都往前移动。所以通过 j-- 来达到正常效果。

方案三:基于对象去重(推荐)

let arr = [1, 2, 1, 1, 1, 2, 3, 3, 3, 2];
let obj = {};
for (let i = 0; i < arr.length; i++) {
  let item = arr[i];
  if (obj[item]) {
    // 将最后一项填补当前项
    arr[i] = arr[arr.length - 1];
    // 数组长度减 -1
    arr.length--; 
    // 索引减 -1
    i--;
  }
  obj[item] = item;
}
console.log(arr); // [1, 2, 3]

方案四:基于 Set 去重(推荐)

Set 是 ES6 的新语法,可以去掉重复的元素。

let arr = [1, 2, 1, 1, 1, 2, 3, 3, 3, 2];

arr = new Set(arr);
console.log([...arr]); // [1, 2, 3]
console.log(Array.from(arr)); // [1, 2, 3]

方案五:filter + indexOf(推荐)

使用 Array.filterindexOf() 来实现。

const array = [1, 1, 2, 3, 5, 5, 1];
let newArr = array.filter((arr, index) => array.indexOf(arr) === index);
console.log(newArr); // [1, 2, 3, 5]

数组截断

如果你想从数组末尾删除值(删除数组中的最后一项),有比使用 splice() 更快的替代方法。

例如,你知道原始数组的大小,可以重新定义数组的 length 属性的值,就可以实现从数组末尾删除值。

let array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(array.length); // 10

array.length = 4;
console.log(array); // [0, 1, 2, 3]

还可以使用 slice() 方法。

let array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(array.length); // 10

let newArr = array.slice(0, 3);
console.log(array); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log(newArr); // [0, 1, 2]

过滤掉数组中的 falsy 值

falsy 值(虚值)是在 Boolean 上下文中认定为 false 的值。

在 JavaScript 中只有 8 个 falsy 值:

  • false、0、-0、0n、""、''、``、null、undefined、NaN
const array = [0, 1, "0", "1", "大漠", '', -0, "w3cplus.com", undefined, true, ``, false, null, "undefined", "null", NaN, "NaN", "1" + 0, ""];

let newArr = array.filter(Boolean);
console.log(newArr); // [1, "0", "1", "大漠", "w3cplus.com", true, "undefined", "null", "NaN", "10"]

获取数组的最后一项

数组的 slice() 取值为正值时,从数组的开始处截取数组的项,如果取值为负整数时,可以从数组末属开始获取数组项。

let array = [1, 2, 3, 4, 5, 6, 7];
let newArr1 = array.slice(-1);
console.log(newArr1); // [7]

let newArr2 = array.slice(array.length - 1);
console.log(newArr2); // [7]

清空数组

let array = [1, 2, 3, 4];
// 第一种
array = [];

// 第二种
array.length = 0;

使用 ... 运算符合并对象或数组中的对象

合并对象

const obj1 = {
  name: "Tom",
  sex: "男"
};

const obj2 = {
  name: "Rose",
  age: 30
};

const mergeObj = { ...obj1, ...obj2 };
console.log(mergeObj); // { name: 'Rose', sex: '男', age: 30 }

const mergeObj2 = Object.assign({}, obj1, obj2);
console.log(mergeObj2); // { name: 'Rose', sex: '男', age: 30 }

const mergeObj3 = {};
Object.assign(mergeObj3, obj1, obj2);
console.log(mergeObj3); // { name: 'Rose', sex: '男', age: 30 }

合并数组中的对象

使用 reduce 方法,第二个参数传空对象 {}

const array = [
  {
    name: "Tom",
    age: 20
  },
  {
    name: "Rose",
    age: 25
  }
];

const result = array.reduce((acc, item) => {
  return {
    ...acc,
    [item.name]: item.age
  };
}, {});
console.log(result); // { Tom: 20, Rose: 25 }

有条件的添加对象属性

const getUser = isIncluded => {
  return {
    name: "Tom",
    age: 20,
    ...(isIncluded && { info: "我是Tom" })
  };
};

const user = getUser(true);
console.log(user); // { name: 'Tom', age: 20, info: '我是Tom' }

const user2 = getUser(false);
console.log(user2); // { name: 'Tom', age: 20 }

解构原始数据

在使用数据的时候,把所有数据都放在一个对象中,同时想在这个数据对象中获取自己想要的数据,在这里可以使用 ES6 的 Destructuring 特性来实现。

比如你想把下面这个 obj 中的数据分成两个部分:

const obj = {
  name: "Rose",
  age: 22,
  sex: "女",
  email: "xxx@163.com",
  birthday: "1995-03-10"
};

let user = {};
let userInfo = {};

({ name: user.name, age: user.age, sex: user.sex, ...userInfo } = obj);

console.log(user); // { name: 'Rose', age: 22, sex: '女' }
console.log(userInfo); // { email: 'xxx@163.com', birthday: '1995-03-10' }

动态更改对象的 key

在对象中,使用 [] 包裹动态传入的 key

const dynamicKey = "email";
let obj = {
  name: "Rose",
  age: 22,
  sex: "女",
  [dynamicKey]: "xxx@163.com"
};

console.log(obj); // { name: 'Rose', age: 22, sex: '女', email: 'xxx@163.com' }

判断对象的数据类型

使用 Object.prototype.toString.call() 配合闭包来实现对象数据类型的判断。

function isType(type) {
  return function (target) {
    return `[object ${type}]` === Object.prototype.toString.call(target);
  };
}

const isArray = isType("Array")([1, 2, 3]);
console.log(isArray); // true

const isBoolean = isType("Boolean")("");
console.log(isBoolean); // false

简化写法:

const isType = type => target => `[object ${type}]` === Object.prototype.toString.call(target);

const isArray = isType("Array")([1, 2, 3]);
console.log(isArray); // true

const isBoolean = isType("Boolean")("");
console.log(isBoolean); // false

in 关键字的使用

判断对象是否为【数组/对象】的【元素/属性】

  • 格式:【变量 in 对象】
  • 若“对象”为数组时,“变量”指的是数组的索引;
  • 若“对象”为对象时,“变量”指的是对象的属性;

情况一:数组

let arr = ["a", "b", "2", "3", "str"];
console.log("b" in arr); // false
console.log(4 in arr); // true

情况二:对象

let obj = { a: "one", b: "two", c: "three" };
console.log("b" in obj); // true
console.log(2 in obj); // false