【若川视野 x 源码共读】第36期 | omit.js 剔除对象中的属性

137 阅读3分钟

本文参加了由公众号@若川视野 发起的每周源码共读活动,点击了解详情一起参与。

1. 学习目标

2. 选学资料

3. 学习过程

3.1 如何使用 omit.js 来剔除对象中的方法

  • 安装 omit.js 模块:npm i --save omit.js
    使用如下:
var omit = require('omit.js');
omit({ name'Benjy'age18 }, [ 'name' ]); // => { age: 18 }
  • 安装 lodash, 使用 lodash 中的 _.omit(object, [props])
var object = { 'a': 1, 'b': '2', 'c': 3 };
_.omit(object, ['a', 'c']); 
// => { 'b': '2' }

3.2 omit.js 源码

function omit(obj, fields) {
  // eslint-disable-next-line prefer-object-spread
  const shallowCopy = Object.assign({}, obj);
  for (let i = 0; i < fields.length; i += 1) {
    const key = fields[i];
    delete shallowCopy[key];
  }
  return shallowCopy;
}

export default omit;

3.3 举例

  • 删除object对象的属性
const obj = { name: 'Benjy', age: 18 };
const result = omit(obj, ['name']);

console.log("obj==", obj); // { name: 'Benjy', age: 18 }
console.log("result==", result); // { age: 18 }

// 使用omit的产生的新对象不改变源对象
console.log("obj === result-->", obj === result); // false
console.log("obj == result-->", obj == result); // false
// 嵌套对象
const obj = { name: 'Benjy', info: { age: 18, number: 10, hobhy: 'fishing' } };
const result = omit(obj, ['name']);

console.log("obj==", obj); 
// 结果:{ name: 'Benjy', info: { age: 18, number: 10, hobhy: 'fishing' } }

console.log("result==", result); // { info: { age: 18, number: 10, hobhy: 'fishing' } }
// 无法剔除 info 对象里面的 age、number、hobby 属性
  • 在 TS 中的应用

OmitTypeScript3.5新增的一个辅助类型,
它的作用主要是:以一个类型为基础支持剔除某些属性,然后返回一个新类型。

import omit from 'omit.js';

type Person = {
    name: string;
    age: string;
    hobby: string;
};

type PersonWithoutHobby = omit<Person, 'hobby'>;

// PersonWithoutHobby equal to NormalPerson
type NormalPerson = {
    name: string;
    age: string;
};

4. delete vs omit.js

日常开发中,删除对象中的某个属性,很多同学都是直接使用 delete obj.xxx 的。
那么:

1. delete 和 omit.js 的返回值是什么?

delete 返回的是布尔值(删除成功返回true,删除失败返回false),
omit.js 返回的是 剔除属性后的新对象。

const obj = { name: 'coco', age: 18 };

const result_omit = omit(obj, ['name']); 
console.log("result_omit==", result_omit); // {age: 18}

const result_delete = delete obj.name; 
console.log("result_delete==", result_delete); // true

2. delete 和 omit.js 删除不存在的属性,返回值是什么?

delete返回的是 true,omit.js 返回的是删除前的对象。

const obj = { name: 'coco', age: 18 };
const result_omit = omit(obj, ['p']);
console.log("result_omit==", result_omit); // { name: 'coco', age: 18 }

const result_delete = delete obj.p;
console.log("result_delete==", result_delete); // true

3. delete 不能删除原型上的属性,omit.js 也不能删除原型上的属性

omit.js 用的 Object.assign() 是浅拷贝,不拷贝原型上的属性, 所以也就不能删除原型属性了。

function Foo() {
    this.name = 'coco';
}

Foo.prototype.age = 18;
const foo = new Foo(); // foo为 {name:'coco'}

console.log("foo.age==", foo.age); // 18
console.log(delete foo.age); // true
console.log("foo.age==", foo.age); // 18

 console.log(omit(foo, ['age'])); // 删除不存在的属性age,返回的是删除前的属性 {name: 'coco'}
 console.log(omit(foo, ['lala'])); // 删除不存在的属性age,返回的是删除前的属性 {name: 'coco'}

4. delete 不能删除一个变量

let a = 88;
console.log(delete a); // false
console.log(omit(a, ['a'])); // {}

5. delete 删除数组某个数据,数组长度不会变化

  • delete 删除数组的某一项,并不会导致数组长度变短。
  • 对应的数据的值会变成 empty,而不是 undefined 或 null
let arr = [1, 2, 3];
console.log("arr.length==", arr.length); // 3
console.log(delete arr[1]); // true
console.log("arr.length==", arr.length); // 3
console.log("arr==", arr); // [1, empty, 3]

empty 是“未初始化”的意思。

  • new Array(2) 会得到 [empty x 2]
  • forEach 和 in 并不会对未初始化的值进行任何操作。

6. 哪些属性不能被 delete 删除?

  • varconstlet 声明的全局变量
  • 数据属性 configurable: false 的属性
  • 原型上的属性
  • 函数参数
  • 一些常量(NaN、Infinity、undefined)
  • 函数声明

JavaScript中delete操作符不能删除的对象

5. 总结

对 omit.js 有了初步的认识,也对delete 和 omit.js 做了简单的比较。 也就是说: delete 返回 false 一定删除失败了;delete 返回 true 不一定删除成功了。而且,delete 有很多不能删除的对象,也不能直接释放内存。

综上所述,日后若遇到删除对象中某个属性的时候,推荐使用 omit 方法(lodash的omit方法或者 omit.js)。