`Object.keys` have different result than `Reflect.ownKeys` when using `NewProxy`
zyxkad opened this issue · 3 comments
I want to implement something like the Storage API.
This is what I'm doing right now:
type Storage interface {
Len()(int)
Keys()(keys []string)
GetItem(key string)(value goja.Value)
SetItem(key string, value goja.Value)
RemoveItem(key string)
Clear()
}
func ProxyStorage(s Storage, vm *goja.Runtime)(goja.Proxy){
getitem := vm.ToValue(s.GetItem)
setitem := vm.ToValue(s.SetItem)
removeitem := vm.ToValue(s.RemoveItem)
clear := vm.ToValue(s.Clear)
o := vm.NewObject()
o.Set("test", 234)
return vm.NewProxy(o, &goja.ProxyTrapConfig{
IsExtensible: func(_ *goja.Object)(success bool){
return true
},
Has: func(_ *goja.Object, property string)(available bool){
switch property {
case "length", "getItem", "setItem", "removeItem", "clear":
return true
}
return s.GetItem(property) != nil
},
Get: func(_ *goja.Object, property string, receiver goja.Value)(value goja.Value){
switch property {
case "length":
return vm.ToValue(s.Len())
case "getItem":
return getitem
case "setItem":
return setitem
case "removeItem":
return removeitem
case "clear":
return clear
}
return s.GetItem(property)
},
Set: func(_ *goja.Object, property string, value goja.Value, receiver goja.Value)(success bool){
s.SetItem(property, value)
return true
},
DeleteProperty: func(_ *goja.Object, property string)(success bool){
s.RemoveItem(property)
return true
},
OwnKeys: func(_ *goja.Object)(object *goja.Object){
println("called OwnKeys")
object = vm.ToValue(s.Keys()).ToObject(vm)
object.Set("testKey", "test value")
return
},
})
}
But when I calling Object.keys(storage)
from js, it actually called the OwnKeys
function, but retuned a new empty array.
However, when I use Reflect.ownKeys(stroage)
, it returned exactly what it should return (a non empty array).
Also, when I call Runtime.ToValue(proxiedStorage).ToObject(runtime).Keys()
from go, it didn't invoke the OwnKeys
at all.
I don't know what's wrong here.
But when I calling
Object.keys(storage)
from js, it actually called theOwnKeys
function, but retuned a new empty array. However, when I useReflect.ownKeys(stroage)
, it returned exactly what it should return (a non empty array).
Object.keys()
and Reflect.ownKeys()
are not the same, the former only returns enumerable string properties, the latter returns all string and symbol properties.
Since you have not defined the GetOwnPropertyDescriptor
trap, all properties are considered non-enumerable. You'd get exactly the same behaviour if you wrote it in javascript.
Also, when I call
Runtime.ToValue(proxiedStorage).ToObject(runtime).Keys()
from go, it didn't invoke theOwnKeys
at all. I don't know what's wrong here.
Please provide a runnable test case.
Also, when I call
Runtime.ToValue(proxiedStorage).ToObject(runtime).Keys()
from go, it didn't invoke theOwnKeys
at all. I don't know what's wrong here.Please provide a runnable test case.
I was wrong, the OwnKeys
was called, but the Keys
didn't return anything.
package main
import (
"fmt"
"github.com/dop251/goja"
)
func main() {
vm := goja.New()
proxied := ProxyStorage(vm)
keys := vm.ToValue(proxied).ToObject(vm).Keys()
fmt.Println("keys:", keys)
}
func ProxyStorage(vm *goja.Runtime)(goja.Proxy){
return vm.NewProxy(vm.NewObject(), &goja.ProxyTrapConfig{
OwnKeys: func(_ *goja.Object)(object *goja.Object){
fmt.Println("OwnKeys has been called")
return vm.ToValue([]string{"a", "b", "c"}).ToObject(vm)
},
})
}
Output:
$ go run .
OwnKeys has been called
keys: []
Since you have not defined the
GetOwnPropertyDescriptor
trap, all properties are considered non-enumerable. You'd get exactly the same behaviour if you wrote it in javascript.
Got it, it works for me, thanks :)