JavaScript Proxy which returns 默认为空数组
JavaScript Proxy which returns an empty array by default
我想定义一些对象,以便每个 属性 在未定义时提供一个空数组。
示例:考虑用户列表,每个用户都是 {id: number, age: string, ...}
。我们想按年龄对用户进行分组:
const users = [{id: 1, age: 42}, {id: 2, age: 42}, {id: 3, age: 43}]
const usersByAge = users.reduce((out, user) => {
if (!out.hasOwnProperty(user.age)) {
out[user.age] = []
}
out[user.age].push(user)
return out
}, {})
console.log(usersByAge[42]) -> [{id: 1, age: 42}, {id: 2, age: 42}]
console.log(usersByAge[43]) -> [{id: 3, age: 43}]
console.log(usersByAge[18]) -> undefined
console.log(Object.keys(usersByAge)) -> ['42', '43']
此代码有效,但我想通过使用特殊的 JavaScript 代理来缩短它。如果未定义 属性,它应该 return 一个空数组。即使未定义,也应该可以将项目推入 属性 。它应该为不同的未定义属性提供相同的数组:
const getMapFromIdToArray = () => {
return new Proxy({}, {
get: (target, name) => {
if (!target.hasOwnProperty(name)) {
target[name] = []
}
return target[name]
}
})
}
const usersByAge = users.reduce((out, user) => {
out[user.age].push(user) // <- this should work, array initialization should not be required
return out
}, getMapFromIdToArray())
console.log(usersByAge[42]) -> [{id: 1, age: 42}, {id: 2, age: 42}] - OK
console.log(usersByAge[18]) -> [] - OK
console.log(usersByAge[18] === usersByAge[19]) -> true - FAIL
console.log(Object.keys(usersByAge)) -> ['42', '43'] - FAIL
此代码部分有效。如果未定义 属性,则将其初始化为 []。所以 getter 实际上改变了目标。我想避免这种情况。但与此同时,我希望能够在未初始化的情况下调用 .push 未定义的 属性 。有可能实现吗?
It should provide the same array for different undefined properties
我不确定你在这句话中的意思,但你肯定不希望两个不同的属性 return 引用同一个数组,然后将属于不同属性的项目推送到该数组.
If the property is not defined, it's initialized as []. So the getter
actually mutates the target. I would like to avoid this. But the same
time I want to be able to call .push on an undefined property without
initialization. Is it possible to achieve?
我会说是和不是。 push
方法必须在实际数组上工作,并且对象必须持有对该数组的引用,以便稍后检索推送的项目。但是如果你不希望空数组立即在目标对象中创建一个实际的属性,那么你可以将它单独存储在代理中,直到它被变异后请求:
new Proxy({}, {
tempProps: {},
get: (target, name, reciever) => {
if (target.hasOwnProperty(name)) {
return target[name];
}
if (tempProps.hasOwnProperty(name)) {
if tempProps[name].length {
// array is not empty - bring into target
target[name] = tempProps[name];
delete tempProps[name];
return target[name];
} else {
return tempProps[name];
}
}
tempProps[name] = [];
return tempProps[name];
}
})
也可以在 WeakRef 对象中保存对 returned 空数组的引用,这样如果调用者删除对该数组的所有引用,它最终将被垃圾回收.但这似乎不必要地复杂,除非在非常特殊的情况下。
我想定义一些对象,以便每个 属性 在未定义时提供一个空数组。
示例:考虑用户列表,每个用户都是 {id: number, age: string, ...}
。我们想按年龄对用户进行分组:
const users = [{id: 1, age: 42}, {id: 2, age: 42}, {id: 3, age: 43}]
const usersByAge = users.reduce((out, user) => {
if (!out.hasOwnProperty(user.age)) {
out[user.age] = []
}
out[user.age].push(user)
return out
}, {})
console.log(usersByAge[42]) -> [{id: 1, age: 42}, {id: 2, age: 42}]
console.log(usersByAge[43]) -> [{id: 3, age: 43}]
console.log(usersByAge[18]) -> undefined
console.log(Object.keys(usersByAge)) -> ['42', '43']
此代码有效,但我想通过使用特殊的 JavaScript 代理来缩短它。如果未定义 属性,它应该 return 一个空数组。即使未定义,也应该可以将项目推入 属性 。它应该为不同的未定义属性提供相同的数组:
const getMapFromIdToArray = () => {
return new Proxy({}, {
get: (target, name) => {
if (!target.hasOwnProperty(name)) {
target[name] = []
}
return target[name]
}
})
}
const usersByAge = users.reduce((out, user) => {
out[user.age].push(user) // <- this should work, array initialization should not be required
return out
}, getMapFromIdToArray())
console.log(usersByAge[42]) -> [{id: 1, age: 42}, {id: 2, age: 42}] - OK
console.log(usersByAge[18]) -> [] - OK
console.log(usersByAge[18] === usersByAge[19]) -> true - FAIL
console.log(Object.keys(usersByAge)) -> ['42', '43'] - FAIL
此代码部分有效。如果未定义 属性,则将其初始化为 []。所以 getter 实际上改变了目标。我想避免这种情况。但与此同时,我希望能够在未初始化的情况下调用 .push 未定义的 属性 。有可能实现吗?
It should provide the same array for different undefined properties
我不确定你在这句话中的意思,但你肯定不希望两个不同的属性 return 引用同一个数组,然后将属于不同属性的项目推送到该数组.
If the property is not defined, it's initialized as []. So the getter actually mutates the target. I would like to avoid this. But the same time I want to be able to call .push on an undefined property without initialization. Is it possible to achieve?
我会说是和不是。 push
方法必须在实际数组上工作,并且对象必须持有对该数组的引用,以便稍后检索推送的项目。但是如果你不希望空数组立即在目标对象中创建一个实际的属性,那么你可以将它单独存储在代理中,直到它被变异后请求:
new Proxy({}, {
tempProps: {},
get: (target, name, reciever) => {
if (target.hasOwnProperty(name)) {
return target[name];
}
if (tempProps.hasOwnProperty(name)) {
if tempProps[name].length {
// array is not empty - bring into target
target[name] = tempProps[name];
delete tempProps[name];
return target[name];
} else {
return tempProps[name];
}
}
tempProps[name] = [];
return tempProps[name];
}
})
也可以在 WeakRef 对象中保存对 returned 空数组的引用,这样如果调用者删除对该数组的所有引用,它最终将被垃圾回收.但这似乎不必要地复杂,除非在非常特殊的情况下。