我正在尝试模拟 knex 进行测试。一切似乎都有效,但将代理附加到数组作为原型似乎消除了数组的可迭代性。
这是模拟函数。以下内容适用于对象。
const mock = (data) => {
const orgData = structuredClone(data)
Object.setPrototypeOf(
data,
new Proxy(
{},
{
get(_, prop) {
if (prop === 'then') {
return orgData
}
if (typeof prop === 'symbol') {
return orgData
}
return () => mock(orgData)
},
}
)
)
return data
}
const mm = mock([
{
name: 'user',
},
])
const run = async () => {
const res = await mm.select('*').where('name', 'user')
const [first] = res
// ^^^^^
// TypeError: res is not iterable
// at run (.../test.js:35:18)
}
run()
当链前存在
await
时,将调用代理get
,并将then
作为prop
的值。这是最后一次通话。这会正确返回 [ { name: 'user' } ]
。然而,分配给 res
变量的值看起来像这样 { '0': { name: 'user' } }
。我想知道是否可以将 prototype
分配给数组而不使其成为对象。
我是发布这个问题的同一个人。解决方案是根本不设置原型,而是直接代理承诺本身。
const mock = (data) => {
return new Proxy(Promise.resolve(data), {
get(target, prop) {
if (prop in target) {
const promise = Promise.resolve(target)
// NOTE: when `then` is called independently, this will be global so it
// wouldn't be resolved correctly. So here binding the context to the
// function to make it work
return promise.then.bind(promise)
}
return () => mock(target)
},
})
}
const mm = mock([
{
name: 'user',
},
])
const run = async () => {
const res = await await mm.select('*').where('name', 'user')
console.log(res)
const [first] = res
console.log(first)
}
run()
输出:
:!node test.js
[ { name: 'user' } ]
{ name: 'user' }