Проблема заключается в том, что доступ к 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
.Затем, вызов этой функции для объекта проходит через операцию получения прокси снова , ища #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.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());