Javascript 在代理获取处理程序中区分直接访问和内部访问

Javascript 在代理获取处理程序中区分直接访问和内部访问,javascript,ecmascript-6,es6-proxy,Javascript,Ecmascript 6,Es6 Proxy,我有一个数组: const arr = ['a', 'b', 'c'] 我使用get处理程序为该数组创建一个代理,该处理程序将为每个数字n返回索引为n-1的属性。例如,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(p

我有一个数组:

const arr = ['a', 'b', 'c']
我使用
get
处理程序为该数组创建一个代理,该处理程序将为每个数字
n
返回索引为
n-1
的属性。例如,
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]
  }
})
它似乎工作得很好<例如,code>p[2]给出了它应该给出的
'b'
。然而,还有一个问题
Array.prototype.indexOf()
不再正常工作。当我通过
'a'
'b'
时,它确实起作用–它分别返回
1
2
,但对于
'c'
它返回
-1
。原来
indexOf()
也会触发
get
处理程序。通过将
console.log(property)
添加到
get
处理程序中,我们获得了
p.indexOf('c')
的以下输出:

似乎
indexOf()
在内部检查
length
属性,然后将数组从index
0
迭代到
length-1

如果我知道该属性是直接访问的(如
p[2]
)还是内部访问的,那么解决这个问题就很简单了。然后,我可以始终返回
target[property]
进行内部访问(因此代理将是no-op)

如何在代理
get
handler中区分直接访问和内部访问?

我唯一想到的是抛出一个错误,捕捉它并分析它的堆栈。尽管如此,这似乎是一个解决办法,而不是一个实际的解决方案,所以我想避免它,除非没有其他办法

似乎
indexOf()
在内部检查
length
属性,然后将数组从index
0
迭代到
length-1

对。这是所有内置数组方法的行为

如何在代理获取处理程序中区分直接访问和内部访问

你不能

如果我知道该属性是直接访问的还是内部访问的,那么解决这个问题就很简单了

不,那是错误的方法。如果您希望
forEach
的行为与正常循环不同,那么您的语义就会出现问题。也许你真的想截取
.length
属性?或者环绕索引
0
?如果不知道你要解决的问题,我们很难提出任何有用的建议


一个极端的方法是编写所有数组方法的您自己的版本来处理一个索引数组。

正如torazaburo在评论中所建议的,一个可能的解决方案是为
get
处理程序中的
indexOf
属性返回一个不同的函数,并在那里执行必要的操作。具体来说,我们可以使
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']
常数p=新代理(arr{
get:函数(目标、属性、接收者){
如果(属性=='indexOf'){
返回(…参数)=>{
const result=Reflect.apply(target.indexOf、target、args)
返回结果==-1?结果:结果+1
}
}
const parsed=parseInt(属性,10)
if(!Number.isNaN(已解析))返回目标[parsed-1]
返回目标[属性]
}
})

log(p.indexOf('c'))
为什么要逐个采用这些语义?怀念一些基于1的语言吗?@torazaburo我只是在做一点实验,看看是否有可能创建一个索引从1开始而不是从0开始的数组。我想,但不确定,您必须为
indexOf
方法在对象上实现一个get,并进行必要的操作。@torazaburo根据您的建议,我想出了一个方法。你介意我用这个解决方案自己回答这个问题吗?重写所有数组方法有一个很大的缺点(除了必须编写它们之外):这些方法会比本机方法慢。好吧,本机方法在基于零的数组上工作,所以你不能既吃又吃。顺便说一句,他们可能不会慢很多。嗯,我想我可以。请参阅。@Gothdo:这基本上是您自己版本的
indexOf
(可能也很慢,因为闭包使它绑定到
arr
)。
p.indexOf!==p、 indexOf
。哦,最后是
如果(p.indexOf(…)
能像大多数人期望的那样工作:-)@Bergi我忘了。更正。
if (property === 'indexOf') {
  return (...args) => {
    const result = Reflect.apply(target.indexOf, target, args)
    return result === -1 ? result : result + 1
  }
}