本文参加了由公众号@若川视野发起的每周源码共读活动,点击了解详情一起参与。
这是源码共读的第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 运算符不同,该方法会忽略掉那些从原型链上继承到的属性。
备注:
即使属性的值是 null 或 undefined,只要属性存在,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