我有一个数组:
const arr = ['a', 'b', 'c']
我使用get
处理程序为该数组创建代理,该处理程序将为每个数字n - 1
返回带有n
索引的属性。例如,p[1]
将返回'a'
,p[2]
- 'b'
和p[3]
- 'c'
。
const p = new Proxy(arr, {
get: (target, property, receiver) => {
const parsed = parseInt(property, 10)
if (!Number.isNaN(parsed)) return target[parsed - 1]
return target[property]
}
})
似乎工作正常。例如,p[2]
可以提供'b'
。但是,还有另一个问题。 Array.prototype.indexOf()
无法正常工作。当我通过'a'
或'b'
时它会起作用 - 它分别返回1
和2
,但对于'c'
,它会返回-1
。事实证明,indexOf()
也会触发get
处理程序。通过将console.log(property)
添加到get
处理程序,我们可以获得p.indexOf('c')
的以下输出:
'indexOf'
'length'
'0'
'1'
'2'
似乎indexOf()
在内部检查length
属性,然后将数组从索引0
迭代到length - 1
。
如果我知道该属性是直接访问(如p[2]
)还是内部访问,那么解决这个问题将是微不足道的。然后我总是可以返回target[property]
进行内部访问(因此代理将是no-op)。
如何区分代理get
处理程序中的直接访问与内部访问?
我唯一想到的就是抛出一个错误,抓住它并分析它的堆栈。尽管如此,这似乎是一种解决方法而不是实际的解决方案,所以我想避免使用它,除非别无其他。
答案 0 :(得分:1)
似乎
indexOf()
在内部检查length
属性,然后将数组从索引0
迭代到length - 1
。
是。这是所有内置数组方法的行为。
如何在Proxy get handler中区分直接访问和内部访问?
你不能。
如果我知道该属性是直接访问还是内部访问,那么修复它将是微不足道的。
不,这是错误的做法。如果您希望forEach
的行为与普通循环不同,那么您的语义就会出现问题。也许你真的想截取.length
属性?或者包裹索引0
?在不知道你试图解决的问题的情况下,我们几乎无法提出任何有用的建议。
一个极端的措施是编写自己的所有数组方法版本来处理单索引数组。
答案 1 :(得分:1)
正如torazaburo在评论中所建议的,一种可能的解决方案是为indexOf
处理程序中的get
属性返回不同的函数,并在那里进行必要的操作。具体来说,我们可以使indexOf()
方法适用于原始数组,而不是代理;并将1
添加到结果中。
if (property === 'indexOf') {
return (...args) => {
const result = Reflect.apply(target.indexOf, target, args)
return result === -1 ? result : result + 1
}
}
工作代码段:
const arr = ['a', 'b', 'c']
const p = new Proxy(arr, {
get: function(target, property, receiver) {
if (property === 'indexOf') {
return (...args) => {
const result = Reflect.apply(target.indexOf, target, args)
return result === -1 ? result : result + 1
}
}
const parsed = parseInt(property, 10)
if (!Number.isNaN(parsed)) return target[parsed - 1]
return target[property]
}
})
console.log(p.indexOf('c'))
其他数组方法可以类似地修复。