Reputation: 369
I am learning ES6 Proxy, and try to understand param 'receiver' in a get trap, so I tried to console.log the receiver value. But when run in nodeJS, it causes an error:
RangeError: Maximum call stack size exceeded
let proxy = new Proxy({}, {
get (target, key, receiver) {
console.log('receiver:', receiver)
}
})
let obj = Object.create(proxy)
console.log(obj)
I want to know what is causing this error, and how to test receiver
's reference in different situations.
Upvotes: 2
Views: 311
Reputation: 542
TLDR: problem in implementation of console.log
in the chrome/node.js
If we take your code and run in firefox we will see the next:
Object {}
Yes, that's all what will output firefox.
You might ask the question: "What the matter?". We know that the same code in chrome and node.js makes infinite loop and maximum callstack exceeded.
My view of the problem:
Let's take a little edited example of your code:
let proxy = new Proxy({}, {
get (target, key, receiver) {
console.log(key)
}
})
console.log(Object.create(proxy))
Let's see what it will output in the different environments:
Chrome:
{}
Symbol(Symbol.toStringTag)
2 splice
Node.js:
Symbol(nodejs.util.inspect.custom)
Symbol(Symbol.toStringTag)
{}
Firefox:
Object {}
What a twist! Don't you think? Each platform has printed different results. And here we can conclude the only one thing: Every implementation has different behaviour API of the console.log
.
Let's see another example:
let proxy = new Proxy({}, {
get (target, key, receiver) {
console.log(key)
}
})
alert(Object.create(proxy))
In this example I've just changed API from console.log
to window.alert
. Well, go to see results of printing in different environments.
Chrome:
Symbol(Symbol.toPrimitive)
toString
valueOf
Uncaught TypeError: Cannot convert object to primitive value
Firefox:
Symbol(Symbol.toPrimitive)
toString
valueOf
Uncaught TypeError: can't convert Object.create(...) to string
Wow, are you surprised? Same results in both browsers with different engines.
Whatwg doesn't specify how implementations should implement console.log
API exactly, but window.alert
has concrete steps and that why we got same results. And that inspite of window.alert
algorithm doesn't reveal how it should convert arguments to string for printing to the screen in special alert box.
But I can explain how the last example works with proxy unlike with the console.log
.
If you know how js works with objects when it try convert to primitive it will be piece of cake.
There is operation in ECMAScript that is called ToString. When this operation is called (I guess that window.alert
call it to convert its value to string) it runs in further the operation with the name ToPrimitive (this operation is achieved because, we have an object not a primitive value).
Following occurs the next:
Symbol.toPrimitive
property with further its calling to receive its primitive value. If the result of calling Symbol.toPrimitive
is object, then will be throw an error.Symbol.toPrimitive
hasn't been found, then will be call OrdinaryToPrimitive (its order of performing depends on hint
, in our case hint
is "string"
value)hint
is "string"
value then occurs searching and calling the following methods: "toString"
, "valueOf"
. If hint
isn't "string"
value then searching and calling is performed with: "valueOf"
, "toString"
.If the steps above doesn't invoke the error, then returns a primitive value.
So if you notice your attention to example with window.alert
, you notice that the invocation of window.alert
will be the cause of printing the methods that are definetely same as in ToString: Symbol.toPrimitive
, "toString"
, "valueOf"
. And the final is an error that messages about fail of conversion into string.
Conclusion: console.log
has different implementation in engines, some implementation such as chrome inside console.log
may use arguments directly, thats why we observe strange logging from chrome unlike firefox.
Upvotes: 0
Reputation: 567
I hope that the following code will help to solve your problem.
let proxy = new Proxy({}, {
get: function (target, key, receiver) {
console.log('receiver:' + receiver);
}
});
let obj = Object.create(proxy);
console.log(obj);
Here you have create a Proxy object and it makes an infinite loop which never ends.
This error (maximum call stack trace exceed) means that somewhere in your code, you are calling a function which in turn calls another function and so forth, until you hit the call stack limit. This is almost always because of a recursive function with a base case that isn't being met.
+(string concatenation operator) with object will call the toString method on the object and a string will be returned. So, '' + object is equivalent to object.toString(). And toString on object returns "[object Object]".
With , the object is passed as separate argument to the log method. So, this takes much time to provide arguments to the console log by sepertely and makes a "maximum call stack trace exceed" error.
So according to me I hope that this shold be the issue.
Upvotes: 0
Reputation: 40872
The receiver
in get (target, key, receiver)
refers to the Proxy object, so you create an endless loop.
console.log(obj)
tries to log the contents of obj
, so it is iterating over all its keys, and retrieves their value. To get their value, the get
of the Proxy is invoked, and in that get you have console.log('receiver:', receiver)
, and there receiver
refers to obj
, so again it tries to log the contents of obj
, … which results in an endless recursive loop.
If you want to understand the param receiver
in a get trap then you should not use logging, but the debugger, breakpoints, and the variable inspector in the debugger.
Upvotes: 2