Pull to refresh

Comments 49

Когда читал английскую версию это звучало как Comma оператор и я из за моего Bad English подумал то что есть какой то оператор из за которого движок js виснет но когда прочитал статью все встало на свои места
Только сегодня наконец-то прочитал эту статью в оригинале, а тут уже перевод.
Оператор очень запятая близка к оператора

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

З.ы.: И, вообще, начало предложения странное.
Оператор очень запятая близка к оператора и его жена были в основном из за того что я не могу понять как это сделать в домашних условиях и в порядке надзора судебных актов отказано в связи с чем в настоящее время в России в начале ХХ века в России было продано около двух лет назад в России был принят закон о запрете курения в общественных местах и на улицах города и в его окрестностях в том числе и в России в начале ХХ века
(с) scribe.googlelabs.com
Спасибо! Не знал таких подробностей. Еще одна техника нинздя-кодера :)
«Чем больше неочевидных конструкций языка я задействую — тем незаменимей я стану»
Ниндзя — это хорошо. Навыки ниндзи очень пригодятся такому кодеру при встрече с человеком, которому доведется поддерживать такой код.
Если не применять навыки ниндзя при написании комментариев, то скорее всего не пригодятся.
UFO just landed and posted this here
А мне казалось, что любой, кто знает Си (с которым культурно связан жаваскрипт) знает этот оператор.
Оператор запятая выполняет оба оператора (слева на право) и возвращает значение второго оператора.
Не оператора, а операнда и лучше сказать «вычисляет».
С этим, кстати, связан такой довольно забавный пример:
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];

то тот, кто будет поддерживать этот код, будет реже вспоминать вас матом.
UFO just landed and posted this here
Любой дурак может написать код, понятный компьютеру. Хороший программист пишет код, понятный человеку.
Мартин Фаулер
— Ну и «Пишите код, ожидая что его будет поддерживать с замашками маньяка и садиста»
«знающего ваш домашний адрес». Это важно.
У Пола Айриша в блоге как-то встретил:
// 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);
Вот как полезно писать «забавные» твиты, оказывается. :)
Sign up to leave a comment.

Articles