omit.js 剔除对象中的属性

106 阅读1分钟

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

这是源码共读的第36期,链接:juejin.cn/post/711878…

源码

function omit(obj, fields) {
  const shallowCopy = Object.assign({}, obj);
  for (let i = 0; i < fields.length; i += 1) {
    const key = fields[i];
    delete shallowCopy[key];
  }
  return shallowCopy;
}

示例:

omit({name: '张三', age: 18}, [])   // { name: '张三', age: 18 }
omit({name: '张三', age: 18}, ['name'])   // { age: 18 }
omit({name: '张三', age: 18}, ['name', 'age'])   // {}

归纳

Object.assign() 介绍

语法:

Object.assign(target, ...sources)

参数:

target 目标对象,接收源对象属性的对象。

sources 源对象,包含将被合并的属性。

返回值:

返回目标对象。

描述:

Object.assign() 方法将所有 「可枚举的自有属性」 从一个或多个源对象复制到目标对象,返回修改后的对象。

如果目标对象与源对象具有相同的 key,则目标对象中的属性将被源对象中的属性覆盖,后面的源对象的属性将类似地覆盖前面的源对象的属性。

Object.assign() 应用

  • 复制对象
const obj = {name: '张三', age: 18}

// 目标对象:{} 源对象:obj
const copyObj = Object.assign({}, obj)   // {name: '张三', age: 18}
  • 深拷贝问题

假如源对象是一个对象的引用,它仅仅会复制其引用值。

const obj = {name: '张三', edu: {school: 'A1', major: '计算机'}}
const copyObj = Object.assign({}, obj)

// 修改源对象的 name 属性
obj.name = '李四'
console.log(obj) // {name: '李四', edu: {school: 'A1', major: '计算机'}}
console.log(copyObj) // {name: '张三', edu: {school: 'A1', major: '计算机'}}

// 修改源对象引用对象的属性
obj.edu.school = 'A2'
console.log(obj) // {name: '李四', edu: {school: 'A2', major: '计算机'}}
console.log(copyObj) // {name: '张三', edu: {school: 'A2', major: '计算机'}}
  • 合并对象
const o1 = {a: 1}
const o2 = {b: 2}
const o3 = {c: 3}

// 目标对象:o1 源对象:o2 o3
const o4 = Object.assign(o1, o2, o3)

console.log(o1) // { a: 1, b: 2, c: 3 }
console.log(o4) // { a: 1, b: 2, c: 3 }
  • 合并具有相同属性的对象
const o1 = {a: 1, b: 1, c: 1}
const o2 = {b: 2, c: 2}
const o3 = {c: 3}

const o4 = Object.assign({}, o1, o2, o3)

console.log(o4) // { a: 1, b: 2, c: 3 }
  • 拷贝 Symbol 类型属性
const o1 = {[Symbol('id')]: 1}

const o2 = Object.assign({}, o1)

console.log(o2) // { [Symbol(id)]: 1 }
  • 原型链上的属性和不可枚举属性不能被复制
const obj = Object.create({name: 'zhangsan'}, {age: {
  value: 23,
  writable: true,
  enumerable: false, // 不可枚举
  configurable: true,
}, gender: {
  value: '男',
  writable: true,
  enumerable: true, // 可枚举
  configurable: true,
}})

// obj:{age: 23, gender: '男'} => 原型对象 {name: 'zhangsan'}
console.log(obj) // { gender: '男' }
console.log(obj.name) // zhangsan
console.log(obj.age) // 23

const copyObj = Object.assign({}, obj)
console.log(copyObj) // { gender: '男' }
// 原型链上的属性没有被复制
console.log(copyObj.name) // undefined
// 不可枚举属性没有被复制
console.log(copyObj.age) // undefined

可枚举属性

Object.prototype.propertyIsEnumerable()

语法:

obj.propertyIsEnumerable(prop)

参数:

prop 需要测试的属性名。

返回值:

用来表示指定的属性名是否可枚举的布尔值。

描述:

每个对象都有一个 propertyIsEnumerable 方法。此方法可以确定对象中指定的属性是否可以被 for...in 循环枚举,但是通过原型链继承的属性除外。如果对象没有指定的属性,则此方法返回 false

const obj = {name: '张三', age: 18}
// 设置原型
Object.setPrototypeOf(obj, {gender: '男'})

Object.defineProperty(obj, 'mobile', {
  configurable: true,
  enumerable: false, // 不可枚举
  value: 13123456780,
  writable: true,
})

console.log(obj.gender) // 男
console.log(obj.propertyIsEnumerable('name')) // true
console.log(obj.propertyIsEnumerable('age')) // true
console.log(obj.propertyIsEnumerable('mobile')) // false
console.log(obj.propertyIsEnumerable('gender')) // false

自有属性

Object.prototype.hasOwnProperty()

语法:

obj.hasOwnProperty(prop)

参数:

prop 要检测的属性的字符串形式表示的名称,或者 Symbol

返回值:

用来判断某个对象是否含有指定的属性的布尔值 Boolean

描述:

所有继承了 Object 的对象都会继承到 hasOwnProperty 方法。这个方法可以用来检测一个对象是否含有特定的自身属性;和 in 运算符不同,该方法会忽略掉那些从原型链上继承到的属性。

备注:

即使属性的值是 nullundefined,只要属性存在,hasOwnProperty 依旧会返回 true

const obj = {name: '张三', age: 18, address: null}
Object.setPrototypeOf(obj, {gender: '男'})

console.log(obj.hasOwnProperty('name')) // true
console.log(obj.hasOwnProperty('address')) // true
console.log(obj.hasOwnProperty('gender')) // false
console.log(obj.hasOwnProperty('toString')) // false