Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symbol.prototype Comparison Error

Tags:

javascript

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.

like image 440
Lapys Avatar asked May 28 '18 18:05

Lapys


3 Answers

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.

like image 194
Matus Dubrava Avatar answered Nov 11 '22 19:11

Matus Dubrava


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]());
like image 26
Andrew Svietlichnyy Avatar answered Nov 11 '22 20:11

Andrew Svietlichnyy


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

like image 1
ASDFGerte Avatar answered Nov 11 '22 19:11

ASDFGerte