gpt4 book ai didi

javascript - `Proxy` 将 `this[toString]` 与 `this[Symbol.toStringTag]` 混淆

转载 作者:行者123 更新时间:2023-11-29 10:02:08 28 4
gpt4 key购买 nike

它只发生在 #toString 中,并且只有当我(尝试)通过类似 trapmissingMethod 访问它时才会发生。

我有一个名为 createIterface 的工厂,它返回一个包含大量方法的对象的 Proxy。在这些方法中,我有 #toString()#id()#id 返回一个 interface 与调用者具有相同的属性并且工作正常; #toString 应该将我的 interface 转换为字符串,但它失败了。interface 的所有方法 - 包括 #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

抛出的错误表明它不能(隐含地)将 Symbol 转换为 String(这是真的)。问题是,#toString 不是符号。然而,有一个名为 #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]'

如果我在 __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

除了一些奇怪的浏览器错误(我运行的是最新的 Chrome,在撰写本文时版本为 v.71.0.3578.98),我不知道为什么会发生这种情况或如何修复它。

有人可以帮忙吗?

最佳答案

问题是访问interface.toString首先要经过

get: (obj, prop) => Reflect.has(obj, prop)
? Reflect.get(obj, prop)
: Reflect.has(obj[__methods], prop)
...

您期望 interface.toString 在这里通过三元组并到达 _methods,但是 Reflect.has(obj, 'toString') 将评估为 true 因为 Object.prototype.toString。然后,在对象上调用该函数通过代理的 getter 操作再次,搜索要调用的#toStringTag。 getter 遍历了它的所有三元组,但什么也没找到,所以它抛出

console.log(`No #${prop} property exists.`)

因为 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
);

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 obj = Object.create(null);
const createInterface = (...props) => new Proxy(
Object.assign(obj, {
...props,
[__methods]: {
id: () => createInterface (...props),
toString: () => `Interface(${ props.toString() })`
}
})
, missingMethod
);

const interface = createInterface(0, 1, 2);
interface.id(); //works
console.log(interface.toString());

另一种可能性是 getter 执行 hasOwnProperty 检查而不是 Reflect.has 检查(Reflect.has 基本上是与 in 相同,并且 'toString'in 几乎任何对象):

get: (obj, prop) => obj.hasOwnProperty(prop)

const __methods = Symbol.for("__methods");

const missingMethod = ({
get: (obj, prop) => obj.hasOwnProperty(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
console.log(interface.toString());

第三种可能性是确保初始 Reflect.has 找到的属性不是来自 Object.prototype 方法:

get: (obj, prop) => Reflect.has(obj, prop) && Reflect.get(obj, prop) !== Object.prototype[prop]

const __methods = Symbol.for("__methods");

const missingMethod = ({
get: (obj, prop) => Reflect.has(obj, prop) && Reflect.get(obj, prop) !== Object.prototype[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
console.log(interface.toString());

关于javascript - `Proxy` 将 `this[toString]` 与 `this[Symbol.toStringTag]` 混淆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53975350/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com