Как стать автором
Обновить

Комментарии 49

Просветили, спасибо!
Спасибо большое!
Когда читал английскую версию это звучало как Comma оператор и я из за моего Bad English подумал то что есть какой то оператор из за которого движок js виснет но когда прочитал статью все встало на свои места
comma != coma // ;)
Только сегодня наконец-то прочитал эту статью в оригинале, а тут уже перевод.
Оператор очень запятая близка к оператора

«Очень запятая» это более крутой оператор чем обычная запятая :D

З.ы.: И, вообще, начало предложения странное.
Оператор очень запятая близка к оператора и его жена были в основном из за того что я не могу понять как это сделать в домашних условиях и в порядке надзора судебных актов отказано в связи с чем в настоящее время в России в начале ХХ века в России было продано около двух лет назад в России был принят закон о запрете курения в общественных местах и на улицах города и в его окрестностях в том числе и в России в начале ХХ века
(с) scribe.googlelabs.com
Спасибо! Не знал таких подробностей. Еще одна техника нинздя-кодера :)
«Чем больше неочевидных конструкций языка я задействую — тем незаменимей я стану»
Ниндзя — это хорошо. Навыки ниндзи очень пригодятся такому кодеру при встрече с человеком, которому доведется поддерживать такой код.
Если не применять навыки ниндзя при написании комментариев, то скорее всего не пригодятся.
НЛО прилетело и опубликовало эту надпись здесь
А мне казалось, что любой, кто знает Си (с которым культурно связан жаваскрипт) знает этот оператор.
Оператор запятая выполняет оба оператора (слева на право) и возвращает значение второго оператора.
Не оператора, а операнда и лучше сказать «вычисляет».
С этим, кстати, связан такой довольно забавный пример:
alert( typeof(someUndefinedValue) )
alert( typeof(window, someUndefinedValue) )


Как можно видеть, оператор группировки (в простонародье скобки) не вычисляют значения (используемая мною тут терминология несколько отличается от той, что применяется в стандарте) операнда. Поэтому (eval)('la-la-la') и eval('la-la-la') эквиваленты. Зато (0, eval) заставит содержимое скобок вычислиться и в результате мы получим eval, «открепленный» от своего контекста по-умолчанию.
Назначение разделителя запатая — разделение членов в списке.
statement = оператор (присваивания, условный, цикла и т.д).
operator = операция (сложения, возведения в степень, и т.д).
Operator Comma ближе к Оператор Запятая по аналогии с Оператор побитового сдвига влево
statement
1) утверждение; высказывание; формулировка
2) оператор; предложение
operator
1) оператор(см. тж statement); знак операции
Знание оператора запятая это, конечно, хорошо. Но если вместо

return colors[colorIndex++] || colors[colorIndex = 0, colorIndex++];

вы напишете

return colors[(colorIndex++) % colors.length];

то тот, кто будет поддерживать этот код, будет реже вспоминать вас матом.
НЛО прилетело и опубликовало эту надпись здесь
Любой дурак может написать код, понятный компьютеру. Хороший программист пишет код, понятный человеку.
Мартин Фаулер
— Ну и «Пишите код, ожидая что его будет поддерживать с замашками маньяка и садиста»
«знающего ваш домашний адрес». Это важно.
У Пола Айриша в блоге как-то встретил:
// Detect IE in JS using conditional comments
var ie = (function(){
 
    var undef,
        v = 3,
        div = document.createElement('div'),
        all = div.getElementsByTagName('i');
 
    while (
        div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',  // <<< Вот тут
        all[0]
    );
 
    return v > 4 ? v : undef;
 
}());

Автор
Ужас. Для определения IE придумано множество других приемов, которые гораздо короче в написании и работают, не затрагивая DOM модель.
Хм… А сколько из них не используют UA?
Много. Впрочем, я не заметил то, что этот скрипт еще и версию определяет, а альтернативных, не использующих DOM, я не знаю.
Все User Agent известны почему бы их не использовать.
В JavaScript где, в отличии от css/html, возможности велики наоборот отходят от хаков: см. jQuery, UglifyJS 'v'=='\v' всегда переделывает в !1 (Won't Fix bug)…
Просто рано или поздно эти баги/квирксы могут пофиксить (прим. IE9 'v'=='\v'), а вот форма UA не поменяется.
В С++ его еще и перегружать можно, что ведет к очень интересным эффектам, к сожалению, в большинстве своем это рождает говнокод.
Опа, интересная заметка. Спасибо.

Только как интерперататор будет отличать оператор от разделителя?

Например, в следующем вызове я создаю массив с 2-мя элементами 5 и 7 или массив длиной 7?

var a = new Array(5,7);
Вот из-за таких вопросов лучше создавать масивы так:
var a = [5, 7]; //два элемента
var a = Array(n); //n — элементов
и никогда не смешивать :)
А тут в чем разница?
То ли [5, 7] это [(5, 7)]
То ли [5, 7] это [5, 7]

А вот тут нам на помощь приходит приоритет операторов. У запятой самый низкий приоритет из всех операторов, а у квадратных скобок и вызовов функций (скобки в Array() и просто скобки () это не одно и то же) гораздо выше.
да, что скобки и создание нового объекта не одно и то же — понятное дело. Но ваш ответ прояснил ситуацию — дело именно в приоритете, спасиб )
Извините, мое предыдущее сообщение не соответствует действительности.

Тут нет оператора запятой. Я ошибался и дело не в приоритете, а в том, что Array(...) — вызов функции, а [...] — инициализатор массива. Они оба принимают список аргументов с запятой в качестве разделителя. А вот [] как оператор индексирования хоть и имеет больший приоритет, но на операторе-запятой это никак не сказывается.

alert([3,4,5,6][1,2])
В этой записи [3,4,5,6] — инициализатор массива, а [1,2] — оператор индексирования (доступа к свойствам), у которого «аргумент» (операнд) — простое выражение, в вычислении которого участвует оператор-запятая (в первом случае ей было неоткуда взяться, т.к. по ней разбивается список аргументов; исключение составляет выражение в скобках).
да, я тоже ошибся, приняв приоритет за правильный ответ. Контекст — вот более правильно.

Но вопрос тогда остался открытым (я его задал ниже) — как интерпретатор JS отличает в подобных местах, что конструкцию следует рассматривать именно как перечисление двух аргументов, а не как команду обсчитать выражение, в котором участвует оператор запятая. Ведь выражение является валидным аргументом, а оператор запятая — валидна в выражении.
Как я понял из беглого просмотра стандарта,
Список аргументов разбивается по запятым на особые выражения (ВыражениеПрисваивания в документе по ссылке выше), которые не могут содержать оператор-запятую (Зато могут содержать оператор группировки (скобки), которые уже могут содержать выражения (Выражение в терминах стандарта) с оператором-запятой). Поэтому никаких проблем с неопределенным смыслом не возникает. А вот для оператора-группировки «аргумент» (операнд) является Выражением, т.е. позволяет использовать запятую.
Тут дело не в запятой, а в поведении конструктора Array.
В вашем случае создается массив [5, 7] потому, что конструктор Array имеет следующую логику:
1. Если arguments.length === 1 && typeof arguments[0] === 'number' && (arguments[0] < 0 || isNaN(arguments[0]) && !isFinite(arguments[0])), то выбрасывается исключение RangeError
2. Иначе если arguments.length === 1 && typeof arguments[0] === 'number', то создается массив длиной arguments[0]
3. Иначе создается массив из arguments:
new Array(Infinity); // RangeError
new Array(-1); // RangeError
new Array(NaN); // RangeError
new Array(NaN, NaN); // [NaN, NaN]
new Array(undefined); // [undefined]
new Array(1); // [undefined]
new Array(0); // []
new Array(0, 0); // [0, 0]
хехе, вы попались на ту же удочку, что и pietrovich выше :) дело в том, что тут уже не важно, какая логика внутри конструктора, так как тут вопрос о том — что за аргументы передаст этой логике конструкция new Array(5, 7).

Чуть выше ситуация прояснена — дело именно в приоритете, так как запятая самая низкоприоритетная, то тут сработает оператор вызова конструктора и передаст содержимое скобок как 2 аргумента.
хехе, вы попались на ту же удочку
Чуть выше ситуация прояснена — дело именно в приоритете, так как запятая самая низкоприоритетная, то тут сработает оператор вызова конструктора и передаст содержимое скобок как 2 аргумента
Если бы тут был именно Оператор Запятая, а не Разделитель Запятая, то по своей логике (выполняет все операнды и возвращает последний) в массив бы она передала только 7. Помоему, это Вы плохо читали.

Вы утверждаете, что и тут запятая — Оператор Запятая: Math.min(1, 4, 5)?
Вы правы, здесь действительно нет оператора-запятой.
Моя вина, ввел хабраюзера Zerkella в заблуждение.
Не переживайте, все ок. Идею я понял — дело в контексте.
Передаст 5 и 7 потому, что запятая это Разделитель Запятая, а не Оператор Запятая, а скобки это Function Invoke выражение, а не оператор группировки.
Я исчерпывающе ответил на ваш вопрос выше:
Например, в следующем вызове я создаю массив с 2-мя элементами 5 и 7 или массив длиной 7?
var a = new Array(5,7);
Не сердитесь вы так сильно :)

Лучше подскажите, по каким правилам технически при разборе текста интерпретатор отличает оператор запятую от разделителя запятой?

Пример:
alert
( ( 2 * 2, 0 ), 2);
Интерпретатор удаляет все ненужные невидимые символы, ставит где это необходимо запятые, проводит валидацию.
alert((2*2,0),2)
1. Интерпретатор «видит» alert — эта конструкция подходит по описание переменной
2. Видит, что после переменной стоят скобки — первые скобки Function Invoke выражение.
3. Из-за того, что скобки Function Invoke выражение, то воспринимает запятую перед двойкой как Разделитель Запятая (перечисляет список переменных функции).
4. Начинает по очереди резолвить переменные.
4.1. Доходит до первого аргумента (2*2,0) — это выражение. Исходя из приоритета операций (сперва () затем * затем ,) резолвит это выражение — получаем первый аргумент = 0.
4.2. Доходит до второго аргумента — константа (резолвить не надо) = 2.
5. Далее резолвит объект на который указатель alert смотрит (находит только в global scope) если объекта нет, то выдает ошибку ReferenceError.
6. Смотрит, что объект на который ссылается alert есть Callable — вызывает Callable Object aka Function на который ссылается alert с параметрами 0, 2. Если он не Callable, то выбрасывает ошибку TypeError.
7. Дальнейшее поведение alert всем известно.

В зависимости от интерпретатора он может не убрать точку с запятой, тогда в довесок вызовется ещё и «пустой оператор».
Что-то не очень оно элегантно [читабельно] — записывать несколько выражений в одну строчку, вместо многих, что показано в большинстве Ваших примеров.
Еще один пример использования оператора запятая — вызов Function Expression.

Function Declaration (будет ошибка):
function(){}()

Function Expression (как в jQuery):
(function(){})()

Function Expression (с оператором запятая):
1, function(){}()

P.S. На практике я бы использовать не стал :)
я вот даже не знаю, что лучше — Function Expression (как в jQuery) или Function Expression (с оператором запятая). Мне не очень нравится количество скобок в конце такого выражения:
(function () {
    // code
})();

Пока использую через new, но смущает отсутствие глобального контекста в this.
new function () {
    // code
};
Facebook Style
!function (window, document) {
    // code
}(this, document);
Кстати, для выполнения кода в глобальном контексте можно создавать функции через конструктор Function:

var a = {};
(function() {
    new Function("this.alert('If you can read this I must be global!')")();
}).call(a);
Вот как полезно писать «забавные» твиты, оказывается. :)
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации