Why do I get this error:
Uncaught TypeError: Symbol.prototype [ @@toPrimitive ] requires that 'this' be a Symbol
when I run this code?
3 == Symbol.prototype
I'm still trying to work out the reason why by myself and so far using a try-catch
block to hold it down for awhile but I want a reason for the error.
Because performing ==
(sloppy) comparison tries to convert Symbol.prototype
to primitive value using @@toPrimitive
but this will work only with symbol type and Symbol.prototype
is not of a symbol type but has a type of object.
You can do this for example, calling Symbol()
creates a new value that has a type of symbol and therefore can be converted into its primitive value by using @@toPrimitive
.
console.log(Symbol() == 3);
or use ===
instead of ==
(by using strict equality, JS engine will not try to convert Symbol.prototype
to its primitive value)
console.log(Symbol.prototype === 3);
or even compare it to other object using ==
(that will not try to convert symbol.prototype to its primitive value either)
console.log(Symbol.prototype == {});
But the whole testing is rather meaningless because you can't really change Symbol.prototype
so it will never be equal to 3
, therefore you can simply replace your comparison code with just false
.
Doing something like this Symbol.prototype = 3;
will never work since Symbol.prototype
is read-only property of Symbol
function, which is part of a browser's native code.
When you try to compare a primitive (3
) and object (Symbol.prototype
) it calls @@toPrimitive
method on object, as can be seen here:
let obj = {
[Symbol.toPrimitive](){
console.log("@@toPrimitive is called!");
}
}
console.log( 0 == obj )
Symbol.prototype[Symbol.toPrimitive]
throws an error when called on Symbol.prototype
because it wants a symbol as its argument. However, this looks really strange, because symbols are primitives already and don't need such conversion, moreover it simply returns its argument if it's symbol:
let symbol = Symbol();
console.log(symbol === symbol[Symbol.toPrimitive]());
3 == Symbol.prototype
performs the following operations (likely known parts kept short):
Attempt to coerce Symbol.prototype
to a primitive by calling ToPrimitive
with it as argument, which in turn will use Symbol.prototype[@@toPrimitive]
(with this
being set to Symbol.prototype
). This is due to loose equality doing coercion and the first operand being a number.
Symbol.prototype[@@toPrimitive]
in turn calls thisSymbolValue(this value)
. Here you can start noticing the problem, this
is not a Symbol.
thisSymbolValue
is specified to throw a TypeError (no further details, you will also get different messages on chrome and FF[1] for example) when this
is neither a Symbol nor an object with [[SymbolData]].
[1]: "TypeError: [Symbol.toPrimitive] method called on incompatible Object" on my FF 60.0.1
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With