`Proxy` 将 `this[toString]` 与 `this[Symbol.toStringTag]` 混淆
`Proxy` confusing `this[toString]` with `this[Symbol.toStringTag]`
它只发生在 #toString
上,并且只有当我(尝试)通过类似 missingMethod
的 trap
.
访问它时才会发生
我有一个名为 createIterface
的工厂,其中 returns 一个 Proxy
具有大量方法的对象。在这些方法中,我有 #toString()
和 #id()
。 #id
returns 与调用者具有相同属性的 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
returns '[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());
它只发生在 #toString
上,并且只有当我(尝试)通过类似 missingMethod
的 trap
.
我有一个名为 createIterface
的工厂,其中 returns 一个 Proxy
具有大量方法的对象。在这些方法中,我有 #toString()
和 #id()
。 #id
returns 与调用者具有相同属性的 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
returns '[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());