代理将this [toString]与this [Symbol.toStringTag]混淆

时间:2018-12-30 04:49:41

标签: javascript google-chrome tostring symbols proxy-pattern

它仅在#toString上发生,并且仅当我(试图)通过类似missingMethod的{​​{1}}访问它时出现。

我有一个名为trap的工厂,该工厂使用大量方法返回对象的createIterface。在这些方法中,我同时拥有Proxy#toString()#id()返回具有与调用者相同属性的#id,并且效果很好; interface应该将我的#toString转换为字符串,但是失败。 interface的所有方法-包括interface#id-都在#toString属性内。我这样做是为了调试目的:

#Symbol.for("__methods")

抛出的错误表明它不能(隐式)将Symbol转换为String(这是正确的)。事实是,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 不是符号。但是,有一个著名的符号称为#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

除了一些奇怪的浏览器错误(我正在运行最新的Chrome,在撰写本文时,它是71.0.3578.98版),我不知道为什么会这样或如何解决。

有人可以帮忙吗?

1 个答案:

答案 0 :(得分:4)

问题是首先访问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。吸气剂经过所有三元分析,一无所获,因此抛出异常

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());

另一种可能是让吸气剂进行hasOwnProperty检查而不是Reflect.has检查(Reflect.hasin基本相同,而{{1} }将是'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]