Pull to refresh

Comments 48

UFO just landed and posted this here
Это древняя легенда, уже многие годы нет значимой разницы между i < arr.length, i < length, и while(length--)
оптимизаторы умеют это сами абсолютно везде:
jsperf.com/array-length-vs-cached/47

А вот использование for-in вместо for это жесть просто. for-in можно использовать только как итератор по полям объекта, и нельзя для перебора объектов в большой коллекции. Разве что на производительность вообще наплевать:
jsperf.com/for-loop-vs-for-in-loop/48
Ну вообще даже для итерации по полям объекта for… in использовать не надо. В javascript давно уже есть Object.keys().

Если хотим перебрать все свойства объекта делаем так:

var map = {
    'first': 'firstVal',
    'second' : 'secondVal'
};

var fields = Object.keys(map);

fields.forEach(function(field) {
    console.log(map[field]);
});


Проверки на hasOwnProperty не нужны, Object.keys() это уже сделал.

И не только это, Object.keys возвращает ключи V8 как интернализованные строки, что позволяет ему использовать быстро получить значение по такому ключу.
К слову, во втором тесте используется описанный в статье шорткат для if. :)
if (foo !== null || foo !== undefined || foo !== '') {
     bar = foo;
}
bar = foo || '';


на последний пример стоит обратить внимание, подводный камень при использование числовых данных – 0 попадет под замену
А также NaN для числовых и false для булиня :)
числовые факапы самые частые) не раз ловили похожую ситуацию
Без хорошего опыта в работе с JavaScript, лучше всё-таки не изобретать грабли на собственную задницу. И это совет не только новичкам.

foo = 0;
foo = false;

if (foo !== null || foo !== undefined || foo !== '') {
     bar = foo;
}

bar = foo || '';
«За деревьями не видно леса» (с)
Это выражение всегда истинно:

foo !== null || foo !== undefined || foo !== ''

Стоит немного подкорректировать статью
Добавлю свой, вместо того чтобы делать бесконечный цикл с использованием while:

while (true) {
   // body
}


Можно воспользоваться циклом for:

for (;;) {
   // body
}


Суть в том, что при каждой итерации цикла while условие должно вычисляться (на самом деле этого конечно не происходит благодаря оптимизациям), но я предпочитаю именно for (;;)
Приведение строки к числу

var foo = parseFloat('3133.7'),
    bar = parseInt('31337');

var foo = +'3133.7',
    bar = +'31337';



parseInt и + работают не одинаково. + более строгая операция, parseInt же позволяет парсить вот такие строки «123abc».
К слову сказать Вы не правильно используете parseInt. Правильно вызывать
parseInt(str, 10);

иначе без указания основания могут возникать неожиданности.
Попробуйте например parseInt('0x93')
parseInt(str, 10); актуально только для старых браузеров. Проблема была не в вашем примере parseInt('0x93'), ведь вы же явно указали '0х' — использовать восьмеричную систему. Проблема была в ведущем 0, parseInt('093'). А это все вменяемые браузеры обрабатывают корректно.

А если вашем примере использовать основание, как вы предлагаете — parseInt('0x93', 10), получится вообще 0.
if (foo !== null || foo !== undefined || foo !== '') {
     bar = foo;
}
bar = foo || '';


По-джедайски на undefined лучше проверять так:

if(val !== void 0)

В некоторых реализациях ES имеется возможность переопределить значение undefined

Так же строку необходимо «тримать»:

if(val.trim().length)
Кто в здравом уме будет заменять undefined? Разве чтоб намеренно сломать другие скрипты.
Вы предполагаете что в вашей кодовой базе есть сторонние скрипты которые были умышленно написаны так чтобы сломать другие?

А вообще вместо foo !== null || foo !== undefined можно использовать foo != null
Давайте не надо. В молодости javascript был редкостным г-ном, хватит уже тащить все это в современную разработку. Не использовать strict mode можно только если вы мазохист.
Читать сложнее, но экономит десять символов.

А оно того стоит?
Конечно нет. Тем более что многие сокращения делает обфускатор
Согласен с использованием вещей типа замены for на while, if на оператор && и некоторых других, т. к. они действительно повышают читабельность кода для других разработчиков.

А вот вещи типа !0, !1 и тернарный оператор для множества выражений я бы избегал. Если вам важен размер выходного кода — тут уже лучше написать на пару строк больше, чтобы сделать код недвусмысленным и оставить эту грязную работу минификаьорам.
Цените легкость чтения кода выше, чем удобство его написания Даже во время первоначальной разработки программы код приходится читать гораздо чаще, чем писать. Выгода от подхода, повышающего удобство написания кода за счет легкости его чтения, обманчива.

Макконнелл
Итерированние по массиву используя for..in ведёт к тому, что вы итерурете по всем его ключам, а не только индексам.
(var a =[1]; a.foo=«bar»; и тут for..in проитерирует в том числе и по foo). Возможно это плохо, но к примеру, d3.select возвращает массив, на который набиндены всякие методы. И for..in с радостью по ним продётся.
Я бы назвал большую часть из приведенных примеров сборником «bad practices» исключая разьве что arguments и indexOf
Ну, часть изложенного здесь — вполне устоявшиеся идиомы языка. Хотя должен отметить, что другая часть — ад и мрак.
indexOf тот ещё bad practice. Приблизительно половина моих знакомых путается, когда ~, а когда !~
Никому не рекомендую использовать, т.к. читать код с этой штуковиной тяжко.
Я из-за этого обычно расширяю прототип Array методом in
Array.prototype.in = function (val) {
  return Boolean(this.indexOf(val) + 1);
};


P. S. Ну, пока в ES6 не примут метод includes (пока что в черновике).
Вы расширяете прототип массива перечислимым свойством, а кто-то следует вредному совету из статьи и обходит массив через for-in. Даже не знаю что хуже.

Ну а ES6 уже пол года как принят и includes туда никак попасть не может. Это часть черновика ES7.
обходит массив через for-in
Это за гранью добра и зла.
Это часть черновика ES7.
Да, ES7, его я и имел ввиду.
Кое-что имеет смысл, кое-что исключительно вредные советы:

Про for-in по массиву уже писали выше — просто не делайте так никогда.

Math.floor и ~~ — это не одно и тоже. Простой пример:
Math.floor(100000000000000.1)
100000000000000

~~100000000000000.1
276447232

Wat? Тильда — побитовая операция, она приводит операнд к 32 битному целому числу, и уже потом инвертирует биты. Так что используйте тильду только тогда, когда вы точно знаете, что вы делаете.

Slice и arguments — это очень плохие соседи с точки зрения V8. Для того, чтобы ваш код был оптимизирован, с arguments можно делать ровно 3 действия (см. @jsunderhood от Вячеслава Егорова):
  1. arguments[i] — взятие аргумента по индексу
  2. arguments.length
  3. f.apply(x, arguments), где f.apply === Function.prototype.apply

Так что это, к сожалению, распространенный антипаттерн. А самое производительное решение с точки зрение V8 — копировать из arguments в новый массив в ручную, вот таким образом:
var args = new Array(arguments.length);
for (var i = 0;  i < args.length; ++i) {
  args[i] = arguments[i];
}
Тильда здесь не работает потому, что битовые операторы в JavaScript работают лишь с 32-битными значениями.
«распространенный антипаттерн» — но всё же в это надо упереться для начала. А ещё на V8 свет клином не сошелся и оптимизируя под него, можно просесть в остальных браузерах. И главное, сам V8 может измениться, вспомни свои пост про sort, вот и это всё может поменяться. Так что Array.from мой выбор :]
Кстати, реально редко использую Array.from, совсем про него позабыл. Спасибо, что напомнил)
А насчет V8. Забывать про других не стоит, но все чаще возникают ситуации, когда js и его реализация в V8 начинают быть не отделимы (по крайней мере сейчас): V8 самостоятельно используется в большом количестве различных проектов, Node.js, Electron, NW.js, и, конечно, Chrome OS, Extensions and Apps — это целый мир =)
Так да и это печально на самом деле, но если уже твой путь лежит через V8, то тут уже привет IRHydra ;]
Согласись, что если бы существовала одна единственная реализация js — то разработчикам жилось бы пусть менее весло, но значительно проще. Возможно, язык бы не так стремительно развивался, но это уже немного из другой области вопрос =)
За всякие "!!bar; ~~anyNum;condition? bar: baz; ~someArray", особенно в составе большого выражения, последующие разработчики могут и покарать.
Вообще странное желание загадить код, лишь бы сократить его размер. Мнимайзер + сжатие и не надо срать себе же в мозг.
Полезно для разработчиков минимизаторов, типа Google Closure или UglifyJS.
Явное лучше неявного.

!!b
и
Boolean(b)


Второй вариант, хоть и длинее, но сильно понятнее и читаемей.

Не нужно хакать язык, синтаксические конструкции лучше использовать по назначению.

Код обычно пишется не для конкурса/олимпиады, где нужно показать, что ты знаешь все ньюансы языка. Он пишется для людей.
Мне кажется прежде чем называть что то «bad practice»(одни говорят что это плохо читается, другие не понимают) может проблема просто в том что не хотят или не знают должным образом язык. Ведь все относительно, посмотрите на хаскель, кому то покажет он просто адовым, я к тому что если ты знаешь, то уже не кажется что то непонятным.
Не должно быть в обычном (не оптимизированном) коде конструкций, для понимания которых нужно держать в голове всю спецификацию языка на сотни страниц. А оптимизированный код должен быть прокомментирован типа

var intNum = ~~anyNum; // отбрасываем дробную часть и урезаем целую до 32 бит — по ТЗ больше 32 бит быть не может
Меня одного напрягает, что в конструкциях типа:
var i = list.length;
while (i--) {
  var item = list[i];
  // ...
}

в последней итерации произойдёт лишний декремент?
Иногда он конечно нужен, но чаще лучше без него:
var i = list.length;
while (i) {
  var item = list[--i];
  // ...
}

Понятно, что это не даст какого-то улучшения производительности, но так оно как-то правильней что ли.
Ну и раз уж `i` нужна только для цикла, то в идеале вообще так:
for (var i = list.length; i;) {
  var item = list[--i];
  // ...
}
Вот из-за таких моментов я вообще предпочитаю не использовать оператор декремента в условии и оператор декремента при указании индекса массива, и честно говоря оператор декремента вообще. Да и неявное приведение типов в условии меня раздражает. И объявление переменных внутри цикла — увы наглая ложь :(.
То есть я конструкции наподобие приведённой выше пишу примерно следующим образом.

var i = list.length;
var item;
while(i >= 0) {
    i -= 1;
    item = list[i];
}


Потому, что сегодня ты используешь оператор декремента, завтра вставишь его туда, где должно стоять определение индекса массива и перепутаешь --i с i--, а послезавтра откроешь для себя недокументированный оператор downto ( --> ) и начнёшь писать ересь наподобие:

for(var i = 10; i --> 0; console.log(i));

А кончится всё тем, что ты решишь, что раз после if только одна строчка, то и скобки фигурные можно не ставить.
Нуегонахрен!
Уважаемая компания Майл.ру

Можете мне прокомметировать это письмо по конкурсу «Каникулы в Калифорнии»:
В первом этапе конкурса «Каникулы в Калифорнии» вы ответили верно не на все вопросы. Но это не повод расстраиваться! Уверены, в следующий раз вам повезет!
Следите за нашими новостями!


Что это значит?

Т.е. я недостаточно точно угадал слово Паскаль в видео ролике, которое написано открытым текстом?
Или я не смог найти куски картинки, закомментированные в коде главных страничек ваших сайтов?
it.mail.ru/files/23_1n.jpg
it.mail.ru/files/24_2n.jpg
it.mail.ru/files/25_3n.jpg
it.mail.ru/files/26_4n.jpg
it.mail.ru/files/27_5n.jpg
it.mail.ru/files/28_6n.jpg
it.mail.ru/files/29_7n.jpg
it.mail.ru/files/30_8n.jpg

Вот эти? Вы думаете, я мог ошибиться, если даже они пронумерованы не рандомно, а по порядку?

Простите, но этот конкурс больше похож на лохотрон.
Привет! Вам ответили в переписке, что были неправильно высланы ссылки на куски картинки (одна ссылка была дублирована, а одна отсутствовала). Проверка происходит в автоматическом режиме, поэтому результаты изменить не представляется возможным, даже если ошибка была допущена по случайности.
Опять же камень в огород тех, кто разрабатывал конкурс. Я нашел все коды, просто какой-то из них был случайно введен дважды. Там нельзя было просмотреть уже введенные коды, при том, что картинка все равно «собиралась».

И вы уверены, что конкурс для настоящих профессионалов должен быть таким?
Пишите код для людей! Для машин есть аглифаеры! Не делайте из коллеги компилятор и вам будет меньше икаться.
бррр… Жесть. последний тэг как нельзя лучше подходит к этой теме.

По делу, кто может подробно объяснить с примерами и сутью:
Array.apply(null, {length: N}).map(Function.call, Math.random)
Array.apply(null, {length: N}).map(Number.call, Number)

И его реализация для преобразования строки в массив Char-кодов (иммею ввиду String.charCodeAt())
Моя реализация
Array.apply('', Array(str.length)).map(Function.prototype.call, ''.charCodeAt.bind(str)));

В приципе я понимаю кое-как, но хотелось бы подробно, полностью и точно.
Sign up to leave a comment.