Вызывающая функция-член числового литерала - программирование
Подтвердить что ты не робот

Вызывающая функция-член числового литерала

Я пытаюсь вызвать литеральные функции, но я получаю странное поведение.

Рассмотрим этот код, который возвращает true.

   23 === (23)

Когда я пишу, попробуйте следующее.

(23).toFixed(2)

Я получаю ожидаемый результат _23.00_, но когда я пытаюсь 23.toFixed(2), я получаю эту ошибку.

SyntaxError: Неожиданный токен ILLEGAL

Как JavaScript оценивает выражения, которые не могут понять это и почему я получаю эту ошибку?

4b9b3361

Ответ 1

Ответы Greg Hewgill и icktoofay верны во всех отношениях, однако я бы хотел немного опуститься, абстрагироваться: давайте посмотрим, что на самом деле происходит в соответствии с спецификацией javascript.

Раздел 7.8.3 спецификации определяет числовые литералы. Мы можем видеть следующее:

DecimalLiteral ::
    DecimalIntegerLiteral . DecimalDigits(opt) ExponentPart(opt)
    . DecimalDigits ExponentPart(opt)
    DecimalIntegerLiteral ExponentPart(opt)

DecimalIntegerLiteral ::
    0 
    NonZeroDigit DecimalDigits(opt)

A DecimalLiteral, число - это группа десятичных цифр, возможно, за которой следует точка, за которой, возможно, следуют другие цифры (за которыми может следовать, например, показатель степени e12). Другими словами, 42. является законным и равен 42, а 3e2 равен 300.

Обратите внимание, что если у нас есть точка, мы либо ожидаем, что за ней последует большее количество цифр/экспонентов, или за ней ничего не будет. Однако, и это важная часть, точка является частью числа. Помните об этом, когда мы перейдем к рассмотрению того, как обрабатывается оператор-точка, obj.prop.

Раздел 11.2.1, Аксессоры свойств описывает нотацию точек и скобок для доступа к члену:

MemberExpression . IdentifierName

CallExpression предназначен для вызовов функций, которые нам не нужны. Обратите внимание на то, что мы ожидаем MemberExpression (который может быть DecimalLiteral - но не верьте мне на слово, посмотрите и убедитесь, что я прав).

Увидите эту маленькую точку? Логично перепрыгнуть вперед и сказать "хорошо, там точка в схеме здесь... и там точка в 4.foo... так почему же ошибка?" Увы, мой гипотетический друг, которого я использую для этих предложений, вы забыли, как выглядит DecimalLiteral! Перейдем к двум примерам и посмотрим, что произойдет.

42.foo
^

Каретка представляет символ, в котором мы находимся. До сих пор мы находимся внутри DecimalLiteral / DecimalIntegerLiteral / NonZeroDigit (это довольно много). Перейдите к следующему символу:

42.foo
 ^

Все еще часть номера, совершенно правильная DecimalDigit.

42.foo
  ^

ok, поэтому мы вышли из части DecimalIntegerLiteral. Здесь та же диаграмма на схеме:

DecimalIntegerLiteral . DecimalDigits(opt) ExponentPart(opt)
                      ^

Итак, мы находимся на точке, которая является вполне действительной частью числа. Теперь мы потребляем его, как часть числа, и двигаемся дальше:

42.foo
   ^

f не является ни частью DecimalDigits, ни ExponentPart, теперь мы отстаем от числа. И что теперь? Что это за f? Это не часть ничего. Может быть, это свойство доступа? Посмотрим на схему:

MemberExpression . IdentifierName
      ^

Мы определенно на MemberExpression, но у нас нет точки, которая следует за ней, - эта точка уже является частью числа. Мы достигли синтаксической ошибки: мы прекращаем выполнение и бросаем ее. Надеюсь, вы не живете в стеклянном доме.

Надеюсь, теперь вы поймете, почему работает 42..foo. Когда мы выйдем из MemberExpression, мы столкнемся с другой точкой:

              42..foo
                 ^
MemberExpression . IdentifierName
                 ^

Далее следует совершенно законный IdentifierName.

Конечно, есть несколько других способов отделить точку от числа. Один из способов, как вы показали, состоит в том, чтобы окружать буквальный круглые скобки: (42).foo. Когда мы достигли конца круглых скобок, мы вышли из MemberExpression и на точку. Другой способ - вставить пробел: 42 .foo, так как пространство не может быть частью числа, и оно нейтрально для синтаксического анализатора, поэтому оно не вызывает ошибки.

Ответ 2

В отличие от Ruby (например), парсер Javascript рассматривает . следующие цифры, которые должны быть частью числа. Поэтому парсер видит маркеры:

23. toFixed ( 2 )

который является синтаксической ошибкой, потому что слово toFixed, непосредственно следуя за числом с плавающей запятой, не имеет смысла. Язык, такой как Ruby, который принимает этот синтаксис, будет видеть следующие токены:

23 . toFixed ( 2 )

Ответ 3

Рассмотрим:

5.

Является ли это литералом с плавающей запятой 5. или целым числом 5, за которым следует точка? Вы не знаете; это двусмысленно. JavaScript занимает первое представление. В представлении JavaScript у вас есть литерал с плавающей запятой, за которым следует идентификатор (затем следуют левая скобка, число и правая скобка).

Некоторые люди работают вокруг этого, используя две точки:

23..toFixed(2)

Так как литерал с плавающей запятой может иметь только одну десятичную точку, другая точка является символом точечной точки.