resting 和 spreading 不仅仅可以用于静态参数和数组的扩展。
下面是使用 JavaScript 对象进行 rest 和 spread 时八个鲜为人知的技巧。
克隆一个对象,同时向(浅)克隆对象添加额外的属性。
在这个例子中,user
被克隆,password
被添加到?userWithPass
?中。
const user = { id: 100, name: 'Howard Moon'}
const userWithPass = { ...user, password: 'Password!' }
?
user //=> { id: 100, name: 'Howard Moon' }
userWithPass //=> { id: 100, name: 'Howard Moon', password: 'Password!' }
将两个对象合并成一个新对象。
part1
??和??part2
??合并成??user1
?。
const part1 = { id: 100, name: 'Howard Moon' }
const part2 = { id: 100, password: 'Password!' }
?
const user1 = { ...part1, ...part2 }
//=> { id: 100, name: 'Howard Moon', password: 'Password!' }
对象也可以用以下语法合并:
const partial = { id: 100, name: 'Howard Moon' }
const user = { ...partial, id: 100, password: 'Password!' }
?
user //=> { id: 100, name: 'Howard Moon', password: 'Password!' }
属性可以使用解构和 rest 操作符组合来删除。这里??password
??被解构出来(忽略),属性的??rest
??被返回为??rest
?。
const noPassword = ({ password, ...rest }) => rest
const user = {
id: 100,
name: 'Howard Moon',
password: 'Password!'
}
?
noPassword(user) //=> { id: 100, name: 'Howard moon' }
removeProperty
?函数接受一个?prop
?作为参数。使用计算对象属性名,可以动态地将?prop
?从克隆中排除。
const user1 = {
id: 100,
name: 'Howard Moon',
password: 'Password!'
}
const removeProperty = prop => ({ [prop]: _, ...rest }) => rest
// ---- ------
// \ /
// dynamic destructuring
?
const removePassword = removeProperty('password')
const removeId = removeProperty('id')
?
removePassword(user1) //=> { id: 100, name: 'Howard Moon' }
removeId(user1) //=> { name: 'Howard Moon', password: 'Password!' }
有时属性并不是按照我们需要的顺序排列的,使用一些技巧,我们可以将属性推到列表的顶部或底部。
要将?id
?移动到第一个位置,在展开?object
?之前向新对象添加?id: undefined
?。
const user3 = {
password: 'Password!',
name: 'Naboo',
id: 300
}
?
const organize = object => ({ id: undefined, ...object })
// -------------
// /
// move id to the first property
?
organize(user3)
//=> { id: 300, password: 'Password!', name: 'Naboo' }
要将?password
?移动到最后一个属性,首先从?object
?中销毁?password
?。然后在展开?object
?后设置??password
?。
const user3 = {
password: 'Password!',
name: 'Naboo',
id: 300
}
?
const organize = ({ password, ...object }) =>
({ ...object, password })
// --------
// /
// move password to last property
?
organize(user3)
//=> { name: 'Naboo', id: 300, password: 'Password!' }
默认属性是只有在原始对象中没有包含时才会设置的值。
在这个例子中,user2
?不包含?quotes
?。setDefaults
?函数确保所有对象都设置了?quotes
?,否则将被设置为?[]
?。
当调用?setDefaults(user2)
?时,返回值将包含?quotes: []
。
当调用?setDefaults(user4)
时,因为?user4
?已经有?quotes
?,那个属性将不会被修改。
const user2 = {
id: 200,
name: 'Vince Noir'
}
?
const user4 = {
id: 400,
name: 'Bollo',
quotes: ["I've got a bad feeling about this..."]
}
?
const setDefaults = ({ quotes = [], ...object}) =>
({ ...object, quotes })
?
setDefaults(user2)
//=> { id: 200, name: 'Vince Noir', quotes: [] }
?
setDefaults(user4)
//=> {
//=> id: 400,
//=> name: 'Bollo',
//=> quotes: ["I've got a bad feeling about this..."]
//=> }
如果你想让默认值在最前面而不是最后出现,也可以这样写:
const setDefaults = ({ ...object}) => ({ quotes: [], ...object })
通过结合上述技术,可以创建一个函数来重命名属性。
假设有些对象的?ID
?是大写的,但实际上应该是小写的,首先将?ID
?从?object
?中解构出来,然后在?object
?扩展时将其作为?id
?添加回来。
const renamed = ({ ID, ...object }) => ({ id: ID, ...object })
?
const user = {
ID: 500,
name: "Bob Fossil"
}
?
renamed(user) //=> { id: 500, name: 'Bob Fossil' }
你也可以有条件地添加属性。在这个例子中,只有当?password
?为真时,才会添加?password
?。
const user = { id: 100, name: 'Howard Moon' }
const password = 'Password!'
const userWithPassword = {
...user,
id: 100,
...(password && { password })
}
?
userWithPassword //=> { id: 100, name: 'Howard Moon', password: 'Password!' }
我试着列出了一些不太为人所知的 spread 和 rest 技巧,如果你知道我这里没有列出的技巧,欢迎给我留言。
也欢迎关注公众号:文本魔术,了解更多