`Proxy` confusing `this[toString]` with `this[Symbol.toStringTag]`
It only happens with #toString
, and only when I (try to) access it through a missingMethod
-like trap
.
I have a factory called createIterface
which returns a Proxy
of an object with a large number of methods. Among this methods, I have both #toString()
and #id()
. #id
returns an interface
with the same attributes as the caller and works just fine; #toString
should convert my interface
to a String, but it fails.
All interface
's methods - including #id
and #toString
- are inside a #Symbol.for("__methods")
attribute. I have made it this way for debugging's purpouses:
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
The error throwed says it cannot (implicitly) convert Symbol to String (which is true). Thing is, #toString
is not a Symbol. There is, however, a well-known Symbol called #toStringTag
that defines Object#toString()
behavior. When I implement it with the other methods my #toString()
is ignored and 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]'
If I code the methods outside __methods
it all works fine:
// 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
Other than some weird browse bug (I'm running latest Chrome, which in day of this writing is v. 71.0.3578.98) I have no idea why this is happening or how to fix it.
Could someone help?
javascript google-chrome tostring symbols proxy-pattern
add a comment |
It only happens with #toString
, and only when I (try to) access it through a missingMethod
-like trap
.
I have a factory called createIterface
which returns a Proxy
of an object with a large number of methods. Among this methods, I have both #toString()
and #id()
. #id
returns an interface
with the same attributes as the caller and works just fine; #toString
should convert my interface
to a String, but it fails.
All interface
's methods - including #id
and #toString
- are inside a #Symbol.for("__methods")
attribute. I have made it this way for debugging's purpouses:
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
The error throwed says it cannot (implicitly) convert Symbol to String (which is true). Thing is, #toString
is not a Symbol. There is, however, a well-known Symbol called #toStringTag
that defines Object#toString()
behavior. When I implement it with the other methods my #toString()
is ignored and 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]'
If I code the methods outside __methods
it all works fine:
// 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
Other than some weird browse bug (I'm running latest Chrome, which in day of this writing is v. 71.0.3578.98) I have no idea why this is happening or how to fix it.
Could someone help?
javascript google-chrome tostring symbols proxy-pattern
add a comment |
It only happens with #toString
, and only when I (try to) access it through a missingMethod
-like trap
.
I have a factory called createIterface
which returns a Proxy
of an object with a large number of methods. Among this methods, I have both #toString()
and #id()
. #id
returns an interface
with the same attributes as the caller and works just fine; #toString
should convert my interface
to a String, but it fails.
All interface
's methods - including #id
and #toString
- are inside a #Symbol.for("__methods")
attribute. I have made it this way for debugging's purpouses:
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
The error throwed says it cannot (implicitly) convert Symbol to String (which is true). Thing is, #toString
is not a Symbol. There is, however, a well-known Symbol called #toStringTag
that defines Object#toString()
behavior. When I implement it with the other methods my #toString()
is ignored and 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]'
If I code the methods outside __methods
it all works fine:
// 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
Other than some weird browse bug (I'm running latest Chrome, which in day of this writing is v. 71.0.3578.98) I have no idea why this is happening or how to fix it.
Could someone help?
javascript google-chrome tostring symbols proxy-pattern
It only happens with #toString
, and only when I (try to) access it through a missingMethod
-like trap
.
I have a factory called createIterface
which returns a Proxy
of an object with a large number of methods. Among this methods, I have both #toString()
and #id()
. #id
returns an interface
with the same attributes as the caller and works just fine; #toString
should convert my interface
to a String, but it fails.
All interface
's methods - including #id
and #toString
- are inside a #Symbol.for("__methods")
attribute. I have made it this way for debugging's purpouses:
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
The error throwed says it cannot (implicitly) convert Symbol to String (which is true). Thing is, #toString
is not a Symbol. There is, however, a well-known Symbol called #toStringTag
that defines Object#toString()
behavior. When I implement it with the other methods my #toString()
is ignored and 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]'
If I code the methods outside __methods
it all works fine:
// 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
Other than some weird browse bug (I'm running latest Chrome, which in day of this writing is v. 71.0.3578.98) I have no idea why this is happening or how to fix it.
Could someone help?
javascript google-chrome tostring symbols proxy-pattern
javascript google-chrome tostring symbols proxy-pattern
edited Dec 30 '18 at 5:00
Henrique Guerra
asked Dec 30 '18 at 4:49
Henrique GuerraHenrique Guerra
358
358
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
The problem is that accessing interface.toString
first goes through
get: (obj, prop) => Reflect.has(obj, prop)
? Reflect.get(obj, prop)
: Reflect.has(obj[__methods], prop)
...
You're expecting interface.toString
to fall through the ternary here and get to the _methods
, but Reflect.has(obj, 'toString')
will evaluate to true
because of Object.prototype.toString
. Then, invoking that function on the object goes through the proxy's getter operation again, searching for a #toStringTag
to call. The getter goes through all its ternaries and finds nothing, so it throws on the line
console.log(`No #${prop} property exists.`)
because prop
is a symbol and cannot be concatenated.
One possibility would be to use an object that does not inherit from 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());
Another possibility would be for the getter to do a hasOwnProperty
check instead of a Reflect.has
check (Reflect.has
is basically the same as in
, and 'toString'
will be in
almost any object):
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());
A third possibility would be to make sure the property found by the initial Reflect.has
is not from an Object.prototype
method:
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());
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53975350%2fproxy-confusing-thistostring-with-thissymbol-tostringtag%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
The problem is that accessing interface.toString
first goes through
get: (obj, prop) => Reflect.has(obj, prop)
? Reflect.get(obj, prop)
: Reflect.has(obj[__methods], prop)
...
You're expecting interface.toString
to fall through the ternary here and get to the _methods
, but Reflect.has(obj, 'toString')
will evaluate to true
because of Object.prototype.toString
. Then, invoking that function on the object goes through the proxy's getter operation again, searching for a #toStringTag
to call. The getter goes through all its ternaries and finds nothing, so it throws on the line
console.log(`No #${prop} property exists.`)
because prop
is a symbol and cannot be concatenated.
One possibility would be to use an object that does not inherit from 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());
Another possibility would be for the getter to do a hasOwnProperty
check instead of a Reflect.has
check (Reflect.has
is basically the same as in
, and 'toString'
will be in
almost any object):
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());
A third possibility would be to make sure the property found by the initial Reflect.has
is not from an Object.prototype
method:
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());
add a comment |
The problem is that accessing interface.toString
first goes through
get: (obj, prop) => Reflect.has(obj, prop)
? Reflect.get(obj, prop)
: Reflect.has(obj[__methods], prop)
...
You're expecting interface.toString
to fall through the ternary here and get to the _methods
, but Reflect.has(obj, 'toString')
will evaluate to true
because of Object.prototype.toString
. Then, invoking that function on the object goes through the proxy's getter operation again, searching for a #toStringTag
to call. The getter goes through all its ternaries and finds nothing, so it throws on the line
console.log(`No #${prop} property exists.`)
because prop
is a symbol and cannot be concatenated.
One possibility would be to use an object that does not inherit from 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());
Another possibility would be for the getter to do a hasOwnProperty
check instead of a Reflect.has
check (Reflect.has
is basically the same as in
, and 'toString'
will be in
almost any object):
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());
A third possibility would be to make sure the property found by the initial Reflect.has
is not from an Object.prototype
method:
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());
add a comment |
The problem is that accessing interface.toString
first goes through
get: (obj, prop) => Reflect.has(obj, prop)
? Reflect.get(obj, prop)
: Reflect.has(obj[__methods], prop)
...
You're expecting interface.toString
to fall through the ternary here and get to the _methods
, but Reflect.has(obj, 'toString')
will evaluate to true
because of Object.prototype.toString
. Then, invoking that function on the object goes through the proxy's getter operation again, searching for a #toStringTag
to call. The getter goes through all its ternaries and finds nothing, so it throws on the line
console.log(`No #${prop} property exists.`)
because prop
is a symbol and cannot be concatenated.
One possibility would be to use an object that does not inherit from 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());
Another possibility would be for the getter to do a hasOwnProperty
check instead of a Reflect.has
check (Reflect.has
is basically the same as in
, and 'toString'
will be in
almost any object):
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());
A third possibility would be to make sure the property found by the initial Reflect.has
is not from an Object.prototype
method:
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());
The problem is that accessing interface.toString
first goes through
get: (obj, prop) => Reflect.has(obj, prop)
? Reflect.get(obj, prop)
: Reflect.has(obj[__methods], prop)
...
You're expecting interface.toString
to fall through the ternary here and get to the _methods
, but Reflect.has(obj, 'toString')
will evaluate to true
because of Object.prototype.toString
. Then, invoking that function on the object goes through the proxy's getter operation again, searching for a #toStringTag
to call. The getter goes through all its ternaries and finds nothing, so it throws on the line
console.log(`No #${prop} property exists.`)
because prop
is a symbol and cannot be concatenated.
One possibility would be to use an object that does not inherit from 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());
Another possibility would be for the getter to do a hasOwnProperty
check instead of a Reflect.has
check (Reflect.has
is basically the same as in
, and 'toString'
will be in
almost any object):
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());
A third possibility would be to make sure the property found by the initial Reflect.has
is not from an Object.prototype
method:
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());
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());
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());
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());
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());
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());
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());
answered Dec 30 '18 at 5:33
CertainPerformanceCertainPerformance
82.7k144067
82.7k144067
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53975350%2fproxy-confusing-thistostring-with-thissymbol-tostringtag%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown