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:
- The try to get from object
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.
- If
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)
- If
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 methods haven't been found or the last one from them returns object then throwing an error.
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 convertation 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.