Вызывать методы для нативных типов Javascript без переноса с () - PullRequest
3 голосов
/ 28 апреля 2010

В Javascript мы можем напрямую вызывать методы для строковых литералов, не заключая их в круглые скобки. Но не для других типов, таких как числа или функции. Это синтаксическая ошибка, но есть ли причина, по которой лексеру Javascript необходимо, чтобы эти другие типы были заключены в круглые скобки?

Например, если мы расширяем Number, String и Function с помощью метода alert и пытаемся вызвать этот метод для литералов, это SyntaxError для Number и Function, в то время как он работает для String.

function alertValue() {
    alert(this);
}

Number.prototype.alert = alertValue;
String.prototype.alert = alertValue;
Function.prototype.alert = alertValue;

Мы можем вызвать alert непосредственно для строкового объекта:

"someStringLiteral".alert() // alerts someStringLiteral

но это ошибка синтаксиса для чисел и функций.

7.alert();
function() {}.alert();

Чтобы работать с этими типами, мы должны заключить его в квадратные скобки:

(7).alert(); // alerts "7"
(function() {}).alert(); // alerts "function() {}"

Обновление

Ссылка @Crescent и ответы @Dav и @Timothy объясняют, почему 7.alert() терпит неудачу, так как ищет числовую константу и для ее преодоления вставляет лишние пробелы или лишнюю точку.

7 .alert()
7..alert()
7. .alert();

Существуют ли аналогичные синтаксические причины того, почему функции должны быть заключены в скобки перед вызовом для них метода?

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

7.times { |i| print i }

Обновление 2 :

@ Ответ CMS был точным в понимании того, почему функции не работали выше. Заявления ниже работают:

// comma operator forces evaluation of the function
// alerts "function() {}"
<any literal>, function() {}.alert();​​​​​​​

// all examples below are forced to be evaluated as an assignment expression
var a = function() {}.alert(); 

var b = {
    x: function() { return "property value" }.alert()
}

[ function() { return "array element" }.alert() ];​

Ответы [ 5 ]

6 голосов
/ 28 апреля 2010

Для буквального обозначения Number все остальные ответы указывают вам правильное направление, 7. является действительным DecimalLiteral.

Грамматика говорит о том, что десятичные цифры после первой точки необязательны:

DecimalLiteral ::
DecimalIntegerLiteral . DecimalDigitsopt ExponentPartopt 

* Обратите внимание на дополнительный суффикс

Теперь для функции проблема в том, что она оценивается в контексте оператора .

Существует два допустимых грамматических способа создания функциональных объектов (третий способ создания функций - это использование Function конструктора , но пока это не в тему).

FunctionDeclaration:

function name(/*[param] [, param] [..., param]*/) {
   // statements
}

Выражение функции:

var foo = function /*nameopt*/(/*[param] [, param] [..., param]*/) {
  // statements
};

Грамматика почти идентична, разница в том, где появляется ключевое слово function.

A объявление функции происходит, когда ключевое слово function найдено непосредственно в глобальном коде или в FunctionBody функции.

A выражение функции происходит тогда, когда в контексте выражение найдено ключевое слово function, как и в предыдущем примере, вторая функция является частью AssignmentExpression.

Но у вас на самом деле две проблемы, во-первых, имя FunctionDeclaration обязательно.

Во-вторых, когда вычисляется оператор FunctionDeclaration, точка просто вызовет SyntaxError, потому что точка не ожидается.

Заключение функции в скобки (формально называемое Оператор группировки ) делает функцию, которая будет оцениваться в контексте выражения , выражении функции .

Например, допустимо следующее:

0,function () {}.alert();

Вышеописанное работает, потому что оператор запятой вычисляет выражений .

Вам также следует знать, что FunctionDeclarations оцениваются в «время разбора» (точнее, когда элемент управления входит в Контекст выполнения , с помощью Переменная Instantiation process) и идентификаторы (имена функций) доступны для всей текущей области, например:

foo(); // alerts "foo", function made available at 'parse time'
foo = function () { alert('bar') }; // override with a FunctionExpression
function foo () { alert('foo'); } // FunctionDeclaration
foo(); // alerts "bar", the overriden function

Рекомендуемая статья:

3 голосов
/ 28 апреля 2010

Подсказка: 7. является действительной числовой константой.

1 голос
/ 28 апреля 2010

Лексер ожидает десятичного значения, когда видит число, за которым сразу следует точка. Хотя вы можете проявить «творческий подход» и поставить пробел между цифрами, как в 7 .alert (), но люди, вероятно, будут охотиться за вами, когда они застрянут, поддерживая ваш код!

0 голосов
/ 28 апреля 2010

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

(7).alert();
0 голосов
/ 28 апреля 2010

Используйте десятичную точку, где число ожидает его, и оператор точки будет работать так, как объект ожидает его.

7.0.toFixed (0)

...