Hen*_*rra 3 javascript symbols google-chrome tostring proxy-pattern
它只发生在#toString, 并且只有当我(尝试)通过missingMethod-like访问它时trap。
我有一个工厂createIterface,它返回一个Proxy具有大量方法的对象。在这些方法中,我有#toString()和#id()。#id返回interface与调用者具有相同属性的 并且工作正常;#toString应该将 my 转换interface为字符串,但它失败了。Allinterface的方法——包括#id和#toString——都在一个#Symbol.for("__methods")属性中。我这样做是为了调试的目的:
const __methods = Symbol.for("__methods");
const missingMethod = ({
get: (obj, prop) => Reflect.has(obj, prop)
? Reflect.get(obj, prop)
: Reflect.has(obj[__methods], prop)
? Reflect.get(obj[__methods], prop)
: console.log(`No #${prop} property exists.`)
});
const createInterface = (...props) => new Proxy({
...props,
[__methods]: {
id: () => createInterface (...props),
toString: () => `Interface(${ props.toString() })`
}
}, missingMethod);
const interface = createInterface(0, 1, 2);
interface.id(); //works
interface.toString(); //error: Cannot convert a Symbol value to a string
Run Code Online (Sandbox Code Playgroud)
抛出的错误表示它不能(隐式)将 Symbol 转换为 String (这是真的)。事物是,#toString不是符号。然而,有一个众所周知的 Symbol#toStringTag定义了Object#toString()行为。当我用其他方法实现它时,我#toString()被忽略并interface返回'[object Object]':
// see code above
const createInterface = (...props) => new Proxy({
...props,
[__methods]: {
id: () => createInterface (...props),
toString: () => `Interface(${ props.toString() })`,
[Symbol.toStringTag]: () => "Interface"
}
}, missingMethod);
const interface = createInterface(0, 1, 2);
interface.id(); //works
interface.toString(); //bug: '[object Object]'
Run Code Online (Sandbox Code Playgroud)
如果我__methods对它之外的方法进行编码,一切正常:
// see code above
const createInterface = (...props) => new Proxy({
...props,
id: () => createInterface (...props),
toString: () => `Interface(${ props.toString() })`
}, missingMethod);
const interface = createInterface(0, 1, 2);
const copycat = interface.id();
interface.toString() === copycat.toString(); //true
Run Code Online (Sandbox Code Playgroud)
除了一些奇怪的浏览错误(我正在运行最新的 Chrome,在撰写本文的那天是 v. 71.0.3578.98)我不知道为什么会发生这种情况或如何修复它。
有人可以帮忙吗?
问题是访问interface.toString首先要经过
get: (obj, prop) => Reflect.has(obj, prop)
? Reflect.get(obj, prop)
: Reflect.has(obj[__methods], prop)
...
Run Code Online (Sandbox Code Playgroud)
您希望interface.toString在这里通过三元组并到达_methods,但由于Reflect.has(obj, 'toString')将评估为。然后,在对象上调用该函数再次通过代理的 getter 操作,搜索要调用的对象。getter 遍历它的所有三元组并没有发现任何东西,所以它就上线了trueObject.prototype.toString#toStringTag
console.log(`No #${prop} property exists.`)
Run Code Online (Sandbox Code Playgroud)
因为prop是一个符号,不能连接。
一种可能性是使用不继承自的对象Object.prototype:
const obj = Object.create(null);
const createInterface = (...props) => new Proxy(
Object.assign(obj, {
...props,
[__methods]: {
id: () => createInterface (...props),
toString: () => `Interface(${ props.toString() })`
}
})
, missingMethod
);
Run Code Online (Sandbox Code Playgroud)
get: (obj, prop) => Reflect.has(obj, prop)
? Reflect.get(obj, prop)
: Reflect.has(obj[__methods], prop)
...
Run Code Online (Sandbox Code Playgroud)
另一种可能性是 getter 进行 hasOwnProperty 检查而不是Reflect.has检查(Reflect.has基本上与 相同in,并且几乎'toString'可以是in任何对象):
get: (obj, prop) => obj.hasOwnProperty(prop)
Run Code Online (Sandbox Code Playgroud)
console.log(`No #${prop} property exists.`)
Run Code Online (Sandbox Code Playgroud)
第三种可能性是,以确保由最初发现的财产Reflect.has是不是从一个Object.prototype方法:
get: (obj, prop) => Reflect.has(obj, prop) && Reflect.get(obj, prop) !== Object.prototype[prop]
Run Code Online (Sandbox Code Playgroud)
const obj = Object.create(null);
const createInterface = (...props) => new Proxy(
Object.assign(obj, {
...props,
[__methods]: {
id: () => createInterface (...props),
toString: () => `Interface(${ props.toString() })`
}
})
, missingMethod
);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
353 次 |
| 最近记录: |