Во-первых, обратите внимание, что ваше определение sow
может быть упрощено до:
var sow = Object(Symbol());
, что делает то же самое, что и ваш код в небрежном режиме.
Когда вы звоните String
с аргументом value
, для спецификации :
a. Если NewTarget не определено и Type (значение) равно Symbol, вернуть SymbolDescriptiveString (значение).
b. Давай будем ? ToString (значение).
Здесь, поскольку вы завернули символ в объект, его тип равен , а не символ; скорее это объект, так что ToString
называется. Это, когда вызывается с объектом , сначала приведет объект к примитиву, затем вызовет ToString
для него:
- Пусть primValue будет? ToPrimitive (аргумент, строка подсказки).
- Возврат? ToString (primValue).
Но для символов не может быть вызвано ToString
; как вы можете видеть в той же таблице, когда передано Symbol, ToString
сгенерирует ошибку TypeError.
Вот почему String(sow);
работает. Напротив, когда вы делаете sow.toString()
, вы вызываете Symbol.prototype.toString
с вызывающим контекстом (this
) обернутого объекта символа:
var sow = Object(Symbol());
console.log(sow.toString === Symbol.prototype.toString);
Что делает что-то несколько другое. Symbol.prototype.toString получает базовый Symbol из объекта и затем вызывает SymbolDescriptiveString с Symbol, в результате чего получается строка с описательным значением символа (если есть).
Обратите внимание, что нативный символ , а не , обернутый в объект, не выбрасывает при передаче на String
, потому что String конструктор будет не вызовите проблемный c ToString
абстрактный метод, когда аргумент является символом.
const sym = Symbol();
console.log(String(sym));
console.log(sym.toString());