Пользователь
0,0
рейтинг
3 апреля 2013 в 13:35

Разработка → 24 совета javascript-разработчику перевод

От переводчика: Не смотря на то что оригинал данной статьи датирован январем 2009 года, она не потеряла актуальности и теперь. Я надеюсь что даже те, кто используют JavaScript не первый год, почерпнут для себя что-то полезное.

1. Используйте === вместо ==


В JavaScript существует два разных типа операций сравния: === / !== и == / !=. Считается хорошим тоном всегда использовать первую пару для сравнения.
“Если два операнда одного типа и значения, то === вернет true, а !== false”
JavaScript: The Good Parts


2. Eval = зло


Для тех кто не знаком, функция «eval» дает нам доступ к компилятору JavaScript. Т.е. мы можем выполнить команду записанную в строковой переменной, которую передадим в качестве параметра в eval.
Это не только замедлит вашу программу, но еще и предполагает возниковение огромной дыры безопасности вашего приложения. Это плохо. По возможности избегайте этого.

3. Не используйте короткую запись


Технически можно писать код без фигурных скобок и точек с запятой. Большинство браузеров корректно воспримет следующий код:

if(someVariableExists)  
   x = false


Как насчет этого?

if(someVariableExists)  
   x = false  
   anotherFunctionCall();  


Кто-то может посчитать что это эквивалентно следующему

if(someVariableExists) {  
   x = false;  
   anotherFunctionCall();  
}  


И он будет неправ. Потому что на самом деле для компилятора это выглядит так:

if(someVariableExists) {  
   x = false;  
}  
anotherFunctionCall();  


Как вы заметили отступ маскирует функционал фигурных скобок. Излишне говорить, что это ужасная практика, которую следует избегать любой ценой. Единственное где вы можете опустить использование скобок это в однострочных выражениях, но даже это вызывает кучу споров. (Я против даже такого. Прим. пер.)

if(2 + 2 === 4) return 'nicely done';  


4. Используйте JS Lint


JSLint это анализатор кода (в оригинале debugger, но это не так — прим. пер.), написанный Дугласом Крокфордом. Просто вставьте в него свой код и он быстро проанализирует на предмет возможных проблем и ошибок.
JSLint сканирует JavaScript код. Если он находит проблему, то возвращает сообщение с описанием и местонахождение в коде. Проблема это не обязательно ошибка синтаксиса, хотя часто так и есть. JSLint так-же обращает внимание на соглашения о кодировании а так же на проблемы в структуре. Он не доказывает что ваша программа работает верно.Он просто предоставляет еще один взгляд на ваш код.”
– JSLint Documentation

Прежде чем закоммитить код, прогоните его через JSLint чтобы проверить на наличие ошибок, которые вы могли проглядеть.

Между прочим IDE от JetBrains такие как WebStorm/PyCharm/PHPStorm имеют встроенный анализ JSLint.
image
Таким образом следить за чистотой кода стало еще проще. Прим. пер.


5. Переместите скрипты вниз страницы


Основная цель этого совета — заставить страницу грузиться как можно быстрее. Когда браузер грузит скрипт он не продолжит рендеринг пока весь файл не будет загружен. Таким образом пользователю придется ждать дольше.
Если ваши JS скрипты служать для добавления функционала — например, обработки кликов кнопки то вам стоит перенести скрипты вниз поставив их перед закрывающимся тегом body.
<p>And now you know my favorite kinds of corn. </p>  
<script type="text/javascript" src="path/to/file.js"></script>  
<script type="text/javascript" src="path/to/anotherFile.js"></script>  
</body>  
</html>


6. Объявляйте переменные для 'for" вне циклов


Когда выполняете долгий цикл «for» не заставляйте делать движок больше работы чем нужно.
Плохо

for(var i = 0; i < someArray.length; i++) {  
   var container = document.getElementById('container');  
   container.innerHtml += 'my number: ' + i;  
   console.log(i);  
}  


Обратите внимание как мы должны высчитываем длинну массива для каждой итерации и как мы обходим дерево для поиска #container.
Лучше

var container = document.getElementById('container');  
for(var i = 0, len = someArray.length; i < len;  i++) {  
   container.innerHtml += 'my number: ' + i;  
   console.log(i);  
}  

Тот кто напишет в комментариях как еще можно улучшить этот блок кода пусть возьмет с полки пирожок.

7. Самый быстрый способ получить строку


For это не всегда лучший способ для того чтобы обойти массив или объект. Будьте изобретательны и вы найдете наиболее быстрое решение для текущей задачи.
var arr = ['item 1', 'item 2', 'item 3', ...];  
var list = '<ul><li>' + arr.join('</li><li>') + '</li></ul>';  

Я не собираюсь давать вам скучные бенчмарки, но поверьте мне (или проверьте сами) это действительно самый быстрый способ.

Использование нативных методов (таких как join()), независимо от того что происходит за слоем абстракции гораздо быстрее чем любая ненативная альтернатива.
— James Padolsey, james.padolsey.com


8. Уменьшите количество глобальных переменных


«Сведением количества глобальных переменных к одному, вы значительно снижаете шансы нежелательного взаимодействия с другими приложениями, виджетами или библиотеками.»
— Douglas Crockford

var name = 'Jeffrey';  
var lastName = 'Way';  
  
function doSomething() {...}  
  
console.log(name); // Jeffrey -- or window.name  


Лучше

var DudeNameSpace = {  
   name : 'Jeffrey',  
   lastName : 'Way',  
   doSomething : function() {...}  
}  
console.log(DudeNameSpace.name); // Jeffrey  

Мы уменьшили количество глобальных переменных до одного, странным образом названного, обьекта «DudeNameSpace».

9. Комментируйте ваш код


Это кажется излишним в начале, но поверьте мне вы действительно ХОТИТЕ комменировать ваш код как можно лучше. Что случится когда вы вернетесь к проекту через несколько месяце чтобы обнаружить что не помните что этот кусок кода делаете. Или что будет если ваш коллега будет смотреть ваш код в процессе код-ревью? Всегда, повторяю всегда комментируйте важные части кода.
// Cycle through array and echo out each name.   
for(var i = 0, len = array.length; i < len; i++) {  
   console.log(array[i]);  
}  


10. Воспользуйтесь прогрессивным улучшением (progressive enchantment)


Всегда принимайте во внимание выключенный JavaScript. Очень соблазнительно думать «Большая часть моих пользователей не отключает JS, так что зачем мне беспокоиться». Тем не менее это большая ошибка.
А не пробовали ли вы на момент взглянуть на ваш красивый слайдер с отлюченным Javascript? (Скачайте the Web Developer Toolbar чтобы быстро проверить это.) Он может сломать полностью весь ваш сайт. Проектируйте дизайн сайта предполагая что JS может быть отключен. И уже после этого начинайте улучшать макет используя JavaScript.

Если вы не знакомы с термином «прогрессивное улучшение» то рекомендую обратить внимание на хабрастатью Progressive Enhancement или всё-таки Graceful Degradation. Прим. пер.

11. Не передавайте строку в «SetInterval» или «SetTimeOut»


Рассмотрим следующий код:

setInterval(  
"document.getElementById('container').innerHTML += 'My new number: ' + i", 3000  
);  


Он не только неэффективен, но еще и работает так же как и «eval». Результаты будут такие-же. Вместо этого передавайте функцию в качестве аргумента.

setInterval(someFunction, 3000);  


12. Не используйте оператор with


На первый взгляд оператор with выглядит как неплохая идея. Концепция его в предоставлении более короткого доступа к глубоко вложенным обьектам. Например используя

with (being.person.man.bodyparts) {  
   arms = true;  
   legs = true;  
}  

вместо

being.person.man.bodyparts.arms = true;  
being.person.man.bodyparts.legs= true;  


К сожалению, после некоторого тестирования обнаруживается что установка новых членов ведет себя плохо. Вместо этого используйте такой вариант:

var o = being.person.man.bodyparts;  
o.arms = true;  
o.legs = true;  


13. Используйте {} вместо New Object()


Есть несколько путей для создания объектов в JavaScript. Возможно наиболее традиционный это использование конструктора «new», например

var o = new Object();  
o.name = 'Jeffrey';  
o.lastName = 'Way';  
o.someFunction = function() {  
   console.log(this.name);  
}  


Хотя этот метод получил штамп «плохой практики» он таковой не является. Вместо него, я рекомендую использовать более надежный метод c литералом обьекта

Лучше

var o = {  
   name: 'Jeffrey',  
   lastName = 'Way',  
   someFunction : function() {  
      console.log(this.name);  
   }  
};  


Заметка — если вы хотите создать пустой обьект, то {} сделает это

var o = {};  


Литералы обьектов позволят нам писат код, который поддерживает кучу функционала все еще сохраняя относительную непосредственность. Не нужно больше вызывать конструкторы напрямую или корректировать порядок аргументов переданных в функцию.
— dyn-web.com, http://ww.dyn-web.com/tutorials/obj_lit.php


14. Используйте [] вместо new Array()


Правило выше годится и для массивов.
Нормально

var a = new Array();  
a[0] = "Joe";  
a[1] = 'Plumber';  


Лучше

var a = ['Joe','Plumber'];  

«Распространенная ошибка в JavaSсript программах — использование объекта, где нужен массив или массива где нужен обьект. Простое правило: когда названия свойств это небольшие последовательные числа — используйте массив. В противном случае — объект.
Douglas Crockford


15. Длинный список переменных? Опустите „var“ и используйте запятые


var someItem = 'some string';  
var anotherItem = 'another string';  
var oneMoreItem = 'one more string';  


Лучше


var someItem = 'some string',  
    anotherItem = 'another string',  
    oneMoreItem = 'one more string';  

Этот код должен говорить сам за себя. Я сомневаюсь что тут есть какие-то подвижки в скорости, но код выглядит чище.

17. Всегда, всегда используйте точку с запятой


Технически, большинство браузеров позволят вам не использовать их.

var someItem = 'some string'  
function doSomething() {  
  return 'something'  
}  


Но использование подобную практики потенциально может привести к гораздо более большим и что еще хуже плохо отлавливаемым проблемам.

Лучше

var someItem = 'some string';  
function doSomething() {  
  return 'something';  
}  


Примечание переводчика:
Как правильно указал в комментариях armed в некоторых случаях точка с запятой будет установлена автоматически, причем не так как вы думаете.

Цитата из перевода спецификации ECMA (eng):
Некоторые инструкции ECMAScript (пустая инструкция, объявление переменной, инструкция-выражение, инструкция do-while, инструкция continue, инструкция break, инструкция return, и инструкция throw) должны оканчиваться точками с запятыми. Эти точки с запятыми могут явно указываться в тексте. Однако в некоторых случаях, исходя из соображений удобства, такие точки с запятыми в исходном тексте могут быть опущены. Эти ситуации описываются высказыванием, гласящим, что точки с запятой автоматически вставляются в поток токенов исходного текста в этих ситуациях.


18. Оператор „for… in“


При проходе в цикле через свойстав обьекта вы также обнаружите что получаете в том числе и функции. Для избежания этого необходима проверка с if hasOwnProperty

for(key in object) {  
   if(object.hasOwnProperty(key)) {  
      ...then do something...  
   }  
}  

Из „JavaScript: The Good Parts“ Douglas Crockford.

Вообще Object.prototype.hasOwnProperty проверяет принадлежит ли свойство непосредственно обьекту а не его цепочке прототипов. Подробнее можно почитать в JavaScript Garden
У Ильи Кантора встречается более элегантная форма записи

for(prop in object) if (object.hasOwnProperty(prop)) {
    //...
}

но честно говоря я не уверен какие браузеры могут корректно обрабатывать ее.
Прим. пер.


19. Используйте таймер консоли для оптимизации кода


Нужен быстрый и легкий способ чтобы определить как много времени займет операция? Используйте консольный таймер для логирования результатов.

function TimeTracker(){  
 console.time("MyTimer");  
 for(x=5000; x > 0; x--){}  
 console.timeEnd("MyTimer");  
}


20. Читайте, читайте, читайте...


В то время как я большой фанат блогов по разработке (например этого), это все-таки не заменитель книги для чтения во время обеда или перед сном. Всегда держите книгу по разработке на прикроватной тумбочке. Вот несколько моих любимых по JavaScript-у.

Object-Oriented JavaScript
JavaScript: The Good Parts
Learning jQuery 1.3
Learning JavaScript

Читайте и перечитывайте. Как я!

21. Self-Executing Functions


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

(function doSomething() {
return {
name: 'jeff',
lastName: 'way'
};
})();

Это называется Immediately-Invoked Function Expression. И чаще используется для создания приватной области видимости. Подробнее на JavaScript Garden. Прим. пер.

22. Чистый JavaScript может быть быстрее чем использование библиотек


— Вы готовы дети?
— Да, Капитан!
— Я не слыыышуууу!
—ТАК ТОЧНО, КАПИТАН!
— из заставки к Sponge Bob Square Pants

Не мог не удержаться. Прим. пер.

JavaScript-библиотеки, такие как jQuery и Mootools экономят невероятное количество времени при разработке — особенно при работе с AJAX. Но так же не забывайте что библиотеки никогда не будут такими быстрыми как чистый JavaScript (в случае корректного кода)
Метод jQuery „each“ отлично подходит для циклов, но использование нативного оператора „for“ всегда будет быстрее.

23. JSON.Parse Крокфорда


Несмотря на то что JavaScript 2 должен иметь встроенный парсер JSON, на момент публикации (январь 2009), нам все еще следует включать стороннюю реализацию. Douglas Crockford, создатель JSON, уже создал парсер, который вы можете испольозовать. Его можно загрузить здесь.
После загрузки скрипта у Вас будет доступ к глобальному обьекту JSON, который может быть использован для парсинга соответствующих файлов.

var response = JSON.parse(xhr.responseText);  
  
var container = document.getElementById('container');  
for(var i = 0, len = response.length; i < len; i++) {  
  container.innerHTML += '<li>' + response[i].name + ' : ' + response[i].email + '</li>';  
}  


C момента публикации статьи прошло 4 года, и вы должны подключать стороннюю библиотеку только для IE7 и некоторых мобильных браузеров. caniuse.com/#search=JSON.parse
Второй момент это то, что при использовании jQuery ответы в json автоматически парсятся в обьекты при условии что сервер отдает application-type: „application/json“ или „text/javascript“, а так-же если вы напрямую указали тип ответа в $.get, $.post или $.ajax. При. пер.


24. Уберите „language“


Давным-давно это не было редкой практикой использования аттрибута language у тега script.

<script type="text/javascript" language="javascript">  
...  
</script>  

Сейчас же он считается устаревшим. Избавьтесь от него.

Послесловие переводчика:
Для тех кто действительно хочет в совершенстве овладеть JavaScript-ом рекомендую изучить следующие ресурсы:
Javascript Garden — english, перевод на русский
Современный учебник на javascript.ru — http://learn.javascript.ru/

Я и остальные читатели хабра будут очень рады, если вы добавите свои советы. Наиболее полезные я буду выносить в топик. Спасибо.
Перевод: Jeffrey Way
Максим Сябро @Azy
карма
30,4
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (185)

  • –32
    25. Используейте CoffeeScript
    • +3
      Почему его? Почему не TypeScript? Последний ближе к нативному JS чем, CS от которого явно веет Ruby
      • +3
        От CoffeeScript явно не веет Ruby. Там больше от Yaml и Python.
        • +6
          Я пишу на Python последние 5 лет. Им там не пахнет :)
          • 0
            Я на Ruby второй год, им там тоже не пахнет :)
            • +37
              Из вики:
              CoffeeScript is a programming language that transcompiles to JavaScript. The language adds syntactic sugar inspired by Ruby, Python and Haskell

              Предлагаю тогда свалить все на хаскел, поскольку оба на нем не пишем :)
              • +4
                Вы что, прикалываетесь? Какой Haskell? Его в СS не больше, чем в JS!
                • 0
                  Тогда посмотрите LiveScript — форк CoffeeScript
            • 0
              Ниже я привел общие сходства для Python и Ruby.

              Если говорить о Ruby, то это:
              — именованные операторы (and, or, not, is (также общие и для Python, кроме оператора is)),
              — операторы диапозона (.., ...),
              — операторы определения (?),
              — операторы экзистенциальности (?, ||=, ?=)
              — оператор доступа (@),
              — однострочные комментирии (#, также общие и для Python),
              — инструкции (until, case/when, when, do, unless, super),
              — expression substitution (#{}),
              — диапазоны (ranges)
              — значения по-умолчанию (есть и в Python)
              — необязательный оператор вызова метода ()
              — переменное чисо параметров (splats)
              — возвраемое значение по-умолчанию (return statement)

              и т.д.

              И да, никто не утверждает что CoffeeScript это Ruby или Python.
              • 0
                >> операторы диапозона (.., ...),
                а в пайтоне такого нет?

                >> операторы определения (?),
                это вообще бред полнейший, в руби такого «оператора» нет (если вы не о тернарном операторе конечно), просто в руби имя метода может содержать '?'.

                >> — оператор доступа (@),
                это тихий ужас в cs, в руби @ ссылается на переменную текущего объекта, а в cs оно может ссылаться и на метод, что очень не красиво выглядит.

                >> необязательный оператор вызова метода ()
                ну и что дальше-то? в cs «метод» без этого оператора все равно не вызовется, про убогий do знаю.

                Уже 2 недели пишу на cs и пока так и не понял, мешает он мне или помогает.
                • 0
                  >> операторы диапозона (.., ...),
                  а в пайтоне такого нет?

                  Не совсем, см. Ellipsis и NumPy

                  >> операторы определения (?),
                  это вообще бред полнейший, в руби такого «оператора» нет (если вы не о тернарном операторе конечно), просто в руби имя метода может содержать '?'.

                  1.
                  a = foo? bar
                  


                  var a = typeof foo === "function" ? foo(bar) : void 0;
                  


                  2.
                  a = foo ? bar
                  


                  var a = typeof foo !== "undefined" && foo !== null ? foo : bar;
                  


                  А теперь Ruby:

                  defined? foo
                  defined? foo(bar)
                  


                  Не знаю как вам, но мне кажется что в CS это частично пришло из Ruby.

                  Тернарного оператора (:?) CS, нет также как и Python (

                  Уже 2 недели пишу на cs и пока так и не понял, мешает он мне или помогает.
                  Чем он конкретно он мешает?
                  • 0
                    По поводу '?' я до сих пор не понимаю, причем тут руби :))

                    Вот смотрите, пишем на cs:

                    x = 1
                    if x? then alert(1)

                    оно раскрывается в js:

                    if (x != null) {
                    alert(1);
                    }

                    Более того, '?' в кс что-то совсем уж «глупое», ибо я могу написать x?? и оно раскроется в:

                    if ((x != null) != null) {
                    alert(1);
                    }

                    В руби нет оператора '?', которое можно «впихнуть» в конец переменной :)
                    в руби можно определить метод с? в конце, так же как и с '!' в конце, но это ни на что не повлияет, это типа средство, позволяющее делать имена методов выразительнее. А в cs это реально функциональный юнит. Так что напрасно говорят, что это из мира руби, это из мира ленивых js разработчиков, которые вечно проверяют все и вся на != null и != undefined… :)
                  • 0
                    Ну многое смущает, правда, например эта же история с тем, что я могу написать «x = 1; x?; x????????» и последнее будет валидно и скомпилируется.

                    Они взяли @ из ruby, мол чтобы не писать this, но при этом в руби я всегда знал, что @ -> это объект, а не метод, потому никогда и не пробовал писать `@field()`, в cs'е же постоянно приходится писать `func()`, что выглядит не естественно и создает только путаницу для руби программистов вроде меня.

                    Мне не очень понятен синтаксис опредения функции, `(x) -> ()` — выглядит очень неряшливо и легко теряется в коде.

                    В том же руби: `lambda { |x| }`, или `->(x) {}`
                    или ерланге: fun(x) ->
                    или даже в plain-js: 'function() {}'

                    Короче говоря, cs вроде бы должен был стать удобным и читаемым, но получился перебор, много сахара, слишком много, там где сахар этот вообще не нужен, где-то стало не читаемее, а только хуже.

                    Но и плюсы конечно тоже есть, видимо :))
                    • 0
                      я могу написать «x = 1; x?; x????????» и последнее будет валидно и скомпилируется.

                      Смысла в такой записи не много, но и ошибкой считать это тоже нельзя, хотя можно было бы и ругнуться.

                      Мне не очень понятен синтаксис опредения функции, `(x) -> ()` — выглядит очень неряшливо и легко теряется в коде.
                      Мне наоборот нравится такая запись.

                      Однако ваша запись больше похожа на вызов функции с функциональным аргументом:

                      x -> (x)
                      


                      А определение самовызывающихся лаямбда-функции выглядит так:
                      ((x)->)(x)
                      do (x) -> x
                      


                      И заметьте в отличии от Ruby, метод call опционален!
                      foo = -> 1
                      do foo
                      


                      Такой синтаксис очень удобен для работы с функциональными аргументами:

                      fn -> x
                      

                      Ведь даже такая запись:

                      -> 1
                      


                      Вполне валидна (хотя и бессмыслена)

                      Коль вы упомянули JS, то этот синтаксис основан на будущем стандарте ES6.
                      wiki.ecmascript.org/doku.php?id=harmony:arrow_function_syntax
                      wiki.ecmascript.org/doku.php?id=strawman:block_lambda_revival

                      К сожалению не могу найти ссылку, когда в Python-сообществе обсуждали новый синтаксис для лямбда-выражений. Помню что большая часть предлагали именно подобный синтаксис!

                      но получился перебор, много сахара, слишком много, там где сахар этот вообще не нужен
                      

                      Я бы тоже самое сказал про Ruby )
                      • 0
                        Спасибо за ответ.

                        Тут понимаете в чем дело, js это такой язык, где правят функции высшего порядка, и потому мы постоянно встречаем передачу функций в аргументах, причем определяются эти функции «на месте»:

                        _.select(collection, function(e) { return e > 1 })

                        и все это время что я пробую cs мне очень неудобно писать функции в стиле cs, вот пример:

                        _.select collection, (e) -> e > 1

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

                        _.select collection, fun(e) -> e > 1

                        Было бы как по мне гораздо проще :) Именно поэтому я в руби никогда не использую «короткий» синтаксис определения лямбды `->(e) {}`, а всегда использую классический вариант `lambda { |e| }`, потому что сигнатура заметнее :)

                        Это очень субъективно, но не заметить сигнатуру функции в CS очень просто и мне не нравится это, надеюсь я имею право на такие замечения к авторам языка :)

                        • 0
                          из опыта — просто сделайте перевод строки сразу после стрелки
                          _.select collection, (e) ->
                              e > 1
                          
          • 0
            Частичное сходство все-таки есть:
            Идентация, лямбда-выражения, ленивые вычисления, списочные выражения (array comprehensions), destructuring assignment и пр.

      • +8
        Он решает треть проблем, описанных в статье.
        • –2
          Но синтаксис отличается очень сильно.
          • +1
            Я с этим не спорю. Мне проще за один день запомнить новый синтаксис, чем писать вары и точки с запятой.
      • +1
        на момент публикации (январь 2009)
      • –1
        CS у всех на слуху, следовательно вероятность найти ответ на SO гораздо выше.
      • +2
        Какая разница чем от него веет? Он решает кучу проблем JavaScript, это важно. Правда я мало знаю про TypeScript, может он и лучше. Но что за аргументы «похожее синтаксис», какая разница? Синтаксис изучается за один день.
  • +4
    Я за пирожком!
    var result;
    var container = document.getElementById('container');
    var i = someArray.length;
      
    while (i--) {
      result = 'my number: ' + i + result;  
      console.log(i);
    }
    
    
    • +1
      забыл самое главное:

      container.innerHtml  += result;
      
    • 0
      ИМХО, пока рановато за пирожком (подсказка). Кроме того, у вас будет вывод не в том порядке, что в оригинале (обратный счет)
      • 0
        Ет чо ето не в том? Обратите внимание на способ конкатенации.
        • 0
          Я имел в виду вывод в лог — console.log(i); В оригинале будет прямой счет, у вас — обратный. Конкатенация тут ни при чем.
      • 0
        А, вы за console.log()
        Да кому он тут нужен? ))
      • 0
        Ваша «подсказка» увеличит расстояние до пирожка раз этак в 40 :)
        • 0
          Возможно. Но только тест меня ни в чем не убедил. Какой смысл гонять пустые циклы? Скорее всего, более-менее разумный JS движок их даже сможет оптимизировать и отбросить.
    • +5
      while (i--) намного медленнее, чем for (i = 0; i < someArray.length; ++i) из-за неявного приведения к boolean, проверял когда-то на JSPerf.
      • +1
        Опа, прикольно, будем знать.
        • +1
          И вообще, проверять на 0/не 0 нужно через ===0 и !==0 соответственно. Также и с boolean: ===true и !==true. Этим вы сможете избежать лишнего преобразования типов.
          • 0
            Прикол в том, что если нет преобразования типов, то и строгое равенство не нужно. По факту оно нужно только, если надо проверить соответствие типов, или просто неуверены в том какой тип.
            • 0
              Если писать if (variable), то variable неявно приводится к булевому типу. Если тип переменной заранее неизвестен, то можно писать и так, тогда 0, null, undefined, '', false и некоторые другие вещи будут приводиться к false, съедая производительность. Если тип известен заранее, надо сверять с переменной/константой такого же типа для максимальной производительности.
              • 0
                Это да, но на ту же не переданную переменную в функции можно просто проверять равенством null.

                function(var) {
                    if (var != null) {
                        doCriticalPart(var);
                    }
                    return doGenericPart(var);
                }
                

                null даёт равенство только с null и undefined, и ни с чем больше.
                • 0
                  Да, это исключение. Лично я всегда использую === и !== кроме проверки на null.
      • 0
        А вариант while(i-- > 0)?
      • +1
        А если while(i-->0)?
    • –3
      Не рановато ли за пирожком то?
      Во-первых: не сильно то читаемый код
      Во-вторых: 3 переменные в global scope
      Я бы написал так
      for(
          var i=0, 
              len=someArray.length, 
              container = document.getElementById('container');   
          i<len;
      
          container.innerHTML+='my number: '+i+'<br>', 
          i++
       );
      
      • +1
        Выглядит интересно, но у вас innerHTML в цикле модифицируется
        Ну и читабельность тоже не на высоте
        • 0
          манипулирование innerHTML кусками или за один раз — практически никак (точнее совсем никак), после работы оптимизатора кода и обработчика структуры для корректной вставки в DOM — никак не влияет на скорость и производительность. Проверено на практике на огромных объемах. (И даже если это закешированный в переменную метод jquery, например) А вот лишних переменных во вне конкретного данного случая быть не должно совсем.

          Опять же приведенный мной вариант отлично дружит в плане наглядности с jquery кодом.
          Расшияемость — добавим обертку для .innerHTML как функцию (function(){ })() и вообще красота.
          Отдайте пирожок!!! )
          • +2
            Мой пирожок, не отдам )

            В вашем примере переменные все равно экспортируются в глобальную область видимости.
            Мой код тоже можно завернуть в анонимную функцию; Так что тут 0 — 0
            А касательно манипуляций с DOM, так не важно на сколько быстрей. Важно что быстрей; Вот тест например jsperf.com/accessing-modifying-innerhtml-in-a-loop
            • 0
              Ну ясен пень, что в javascript нет block scope. Имеется ввиду что их там семантически не должно бы быть)
              А ваш тест запустил) Там вообще jquery победил.
              Но вообще, в определенных случаях буфер конечно необходим, но, никак не тут.
          • +1
            а можна и без цикла)))
            container.innerHTML = someArray.join('|').replace(/([^\|]+)\|?/g,function(){return 'my number: '+ (typeof p!='undefined' ? ++p:(p=0))+'<br>'});
            
            • 0
              но за скорость тут не ручаюсь. Не делайте так вообщем )
              • +1
                Не ну можно сделать хитрее:

                'my number:' + join('my number: ') и т огда регулярка не нужна и ваще быстро
                • 0
                  не не)) тут, как бы обрати внимание, не элементы массива выводятся, а их индекс ;)
    • +1
      А можно мне пирожок?
      for (var i = 0, html = '', len = someArray.length; i < len; i++) {
         html += 'my number: ' + i;
      }
      document.getElementById('container').innerHTML = html;
      • –2
        да не нужен тут буфер!
        синтетические тесты такие синтетические.
        И куда он потом этот буфер html? delete? garbage collector'у? А вы в профилировщик заглядывали? delete или garbage collector жрут не мало.

        • 0
          Честно сказать, Ваш вариант намного труднее читается и выполняется. И если насчёт читаемости можно ещё поспорить, то насчёт производительности — нет. Попробуете сделать пару тестов, прежде чем напугать меня (и других) такими «непонятыми» словами.

          Готовый тест: jsperf.com/my-js-patty
          • +4
            Мне это обсуждение очень напоминило обсуждения «оптимизаций» php-кода с заменой двойных кавычек на одинарные. :)

            Да сто раз наплевать, пока профайлер не укажет, что это узкое место.
          • –1
            Я вроде про буфер уже говорил. Не надо в меня тестами кидаться. Вы суть то не уловили:
            в данном примере, происходит инкремент html одного элемента, основанный всего лишь на индексе, не требующий дополнительных вычислений, требующих семантически выделить инкремент (конкатенацию) в блок действий for, а не в блок инициализации.

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

            Добавьте ваш семантически мусорный буфер в мой код и запустите тот же тест. Теперь мой код быстрее.

            На реальной производительности (где на DOM куча вочеров, стилей, событий) наличие буфера никак не сказывается. А вот на «засорение» — да.

            И вот пишут мне потом такие «спичечные» оптимизаторы: «посмотри ка мой код, что-то у меня не пойму все зависает после 15 минут работы, хотя везде все оптимизировано». Хотя не привыкать ловить минусы от непонимающих. Уже даже приятно как-то.
            • 0
              Я вроде про буфер уже говорил.

              Да, говорили. Но в данный конкретный случай я с Вами не согласен.

              Не надо в меня тестами кидаться.

              А что нужно делать? Слепо следовать Вашему примеру и рассказать про сферических коней в вакууме? Нет уж, увольте — я буду использовать тесты чтобы доказать и понять что именно работает быстрее. Ведь именно программирование это то, что нужно всегда тестировать, дабы убедиться, что был выбран лучший вариант. Я вообще не могу представить себе программирование без тестов.

              Вы суть то не уловили [...]

              Не волнуйтесь, я заметил и понял Ваш пример, только автор статьи предлагал написать «как еще можно улучшить этот блок», а не «как втиснуть весь код в блоке for». Более того, я также заметил, что Вы не знаете, как работают переменные в JavaScript, плюс (по моему личную мнению) также не знаете как выглядит «читаемый код».

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

              Может ему и комфортнее там, но почему же не сделать код простым для понимания и в тоже время быстрым для выполнения? И да проверил, и ничуть не уступает, даже наоборот — он будет выполняться чуточку быстрее, если выделять его в блок выполнения (то есть, Ваш код уступает по всем параметрам). Тест jsperf.com/init-block-vs-for-block

              Добавьте ваш семантически мусорный буфер в мой код и запустите тот же тест. Теперь мой код быстрее.

              Стоп-стоп! Ведь Вы предлагали один вариант, а я совсем другой. В итоге, получилось что мой вариант оказался более чем в 600 раз быстрее Вашего именно из-за того, что я использую мусорный буфер. В то время как Вы, скорее всего из-за идеологических соображений, решили что для данного конкретного примера отдельная переменная зло. А теперь, когда Вы поняли свою ошибку, предлагаете мне использовать мой же метод? Нет уже, извините. То, что Вы не знаете как нужно работать с DOM используя JavaScript, это уже Ваша проблема.

              На реальной производительности (где на DOM куча вочеров, стилей, событий) наличие буфера никак не сказывается. А вот на «засорение» — да.

              Опять заблуждаетесь и рассказывайте другим сказки. На «реальной производительности» Ваш метод будет просто убить браузер пользователя и всё. Попробуйте тестировать Ваш пример, используя массив из тысячи элементов и пару десяток HTML элементов.

              И вот пишут мне потом такие «спичечные» оптимизаторы: «посмотри ка мой код, что-то у меня не пойму все зависает после 15 минут работы, хотя везде все оптимизировано».

              А как Вы вообще смеете написать мне такое? Вам совсем не стыдно? Если не заметили, в данный момент Вы являетесь спичечным оптимизаторов, который рассказывает сказки про какой-то там мусор, и бежит от него не понимая как можно оптимизировать простой JavaScript код. И если не заметили, именно Ваш пример зависает после 20 секунд работы (при реальных условия, где не будет использован только один HTML элемент и всего-лишь один массив из 100 компонентов).

  • +3
    Кстати насчет 15 я не согласен, при automerge могут вылезать конфликты. Лучше когда строчки можно добавлять/удалять независимо не затрагивая соседние. И где 16 пункт?
    • 0
      Только сейчас обратил внимание что 16 пункта нет в оригинале :(
      Про автомерж — дельное замечание.
      • 0
        Значит и название статьи теперь не соответствует действительности. Обещали 24 совета, а в реале 23 :) Это как с пельменями, открываешь, а там полпачки — лёд :)
        • 0
          Не. Это больше похоже как сейчас любят делать производители молока — пишут 900 грамм и ставят рядом с литровыми пакетами по такой-же :)
          • 0
            Опаньки, я думал это у нас в Беларуси только.
  • +2
    Понимаю, что перевод, но…

    17-й совет звучит неубедительно. Есть же ASI, являющейся частью спецификации ECMAScript. Слепо надеяться на точки с запятой тоже опасно.

    Код ниже:
    function sum (a, b) {
       return
         a + b;
    }
    

    Ничего не вернет, ибо вступает в дело ASI.

    Вместо того что-бы давать необоснованные, а порой, и вредные советы, лучше бы разжевали как работает ASI.
    Я считаю что наличие точек с запятой или их отсутствие должно относиться к coding style guidelines в рамках проекта или компании, но не более. Это не правило языка программирования.
    Дока: www.ecma-international.org/ecma-262/5.1/#sec-7.9
    • +1
      Да, Вы правы. На ASI нужно сослаться. Не подумал. Сейчас добавлю.
    • –3
      Смысл этого ASI в том, что в середине 90-х решили: ой, если мы введём обязательные точки с запятыми, бедные веб-мастера удавятся от столь сложного синтаксиса.
      Это не должно относиться к coding style, это должно быть обязательным.
      • +1
        Ваше «ой, если мы введём обязательные точки с запятыми, бедные веб-мастера удавятся от столь сложного синтаксиса», конечно же, убедительнее спецификации языка :)
        • –2
          Какая связь между убедительностью моих слов и убедительностью спецификации?
          Основа современной спецификации писалась в тех же 90-х исходя из задач, которые тогда возлагались на язык.
          Одна из задач — сделать язык как можно проще для простых смертных.
          И эта часть спецификации является прямым следствием этого.
          • +2
            Я веду к тому, что в книгах и рекомендациях лучше объяснять, как работает на самом деле, а не как нравится лектору или писателю учебника. Ставить или не ставить точку с запятой это вопрос сугубо холиварный и не более. Правильно написанная программа работает и так и этак. Поэтому точкам с запятой место в coding style guidelines и я не согласен с вашей фразой:
            Это не должно относиться к coding style, это должно быть обязательным.


            Оно будет обязательным только тогда, когда будут (хотя маловероятно) внесены в спецификацию соответствующие изменения.
            • –1
              with, eval и неявное определение глобальных переменных тоже часть спецификации.
              Можно обойтись без любого из представленных здесь пунктов и шансы написать работающую программу всё равно остаются.
              Этоже статья не про то, что у вас без этого не будет запускаться скрипт. Это статья про то, как не быть маргиналом в мире js. Как писать более-менее сложные программы с тем, чтобы если кто-то читал ваш код, он не испытывал брезгливости.
              • +2
                Я понял вашу точку зрения. Но не могу согласиться с тем, что наличие или отсутствие точек с запятой (про with и eval я не говорю) является признаком говнокодерства. Есть прекрасные примеры из open source, с очень большим количеством коммиттеров, где в style guidelines точки с запятой убраны.
  • 0
    7. Нативное vs ненативное здесь не причём. Массив всё равно в цикле собирать придётся. Здесь просто нужно понимать, как строки внутри устроены.
  • +9
    Прямо как Крокфорда перечитал (перевод). Уже лет семь читаю там и сям.

    Неужто ещё есть javascript-разработчики, которые не знают хотя бы большинство пунктов из этого? Не говоря о спорных пунктах вроде спама var или JSON.Parse, когда это уже умеют браузеры. (На дворе не 2009.)
    • +1
      Крокфорд ок. Меня очень раздражает node.js-like отступы в 2 пробела.

      И как я уже писал IE7 не умеет JSON.Parse.
      Если шестерку уже никто не поддерживает, то заказчики иногда требуют поддержки оного.
      • 0
        Гугл уже IE8 не поддерживает, доля IE7 смешна, можно и eval использовать. Часто ли вы получаете JSON, которому не доверяете?
        • –2
          Использование везде JSON это сохранение единого coding-style. Проще для семерки подключить еще одну либу, чем писать обертки с евалом.
          • 0
            Кому-то проще перегрузить IE либами, а кому-то проще написать (грубо)

            JSON.parse = function (text) {
                return eval(text);
            }
            
            • –2
              А обратно? В либе не только парсинг, но еще и сериализация есть.
              • 0
                Про обратное в статье не говорится.
                • –1
                  Но там не говорится о том что используется только JSON.parse.
                  Использовать то о чем не говорилось в свою пользу — явная софистика.
                  • 0
                    Я лишь комментировал статью. Это вы уже уходите от темы.
              • –1
                А где вы видели использование сериализации в JSON? Обычно сериализуют в параметры запроса.
                • –1
                  • –1
                    17% не густо. Скольким из них нужен IE7? Ответ: 138,537 — 2,5% от общего числа.
                    • –1
                      17% чего?
                      На вопрос «кому нужен ие» — я ответил — заказчикам. Более того некоторые корпоративы еще и на ИЕ6 сидят.
                      • –1
                        От 5,9М всего кода. Вы выдали очень частный случай за общий.
        • –1
          Есть рынки, на которых доля покупок через ИЕ7 достигает 30%. JSON.Parse тут самое то
          • 0
            Именно JSON.Parse и никак нельзя eval?
            • –1
              Ранее уже говорили, что иногда еще и stringify нужен.
        • 0
          Доля даже IE6 не смешна, к сожалению, а доверять нельзя даже данным, пришедшим со своего домена :)
          Но я за jQuery.parseJSON, да, там как раз eval с предварительным тестированием, если JSON.parse нет в системе.
      • +1
        А чем плохи 2 пробела?
        • +3
          Читабельность хуже. 2 пробела придумали те кто любят писать лапшекод с кучей колбекэков.
          • +1
            Для вас хуже читаются два, для меня четыре. Кто прав?
            • +1
              В контексте дискуссии «Меня очень раздражает node.js-like отступы в 2 пробела» я, потому что речь шла обо мне.
            • +1
              Прав тот, кто пользуется табами и настраивает размер таба как ему нравится :-р
            • +3
              Мне двух пробелов мало, а четырёх много, так что мой код отличается употреблением трёхпробельного отступа.

              (Правда, на Хабрахабре никто на эту особенность моего кода не обратил ни малейшего внимания за несколько лет — так что важность проблемы, вероятно, преувеличивается.)
              • –1
                Или никто не читает.
          • 0
            Меньше высоты строки, потому плохо читается. Если посмотрите на книги с красной строкой, то там отступ красной строки занимает три символа, потому что меньший не читается.
            • 0
              Меньше высота строки? О чем Вы?
              • +7


                x заметно меньше y.
                • 0
                  а, теперь понял
                  но это вопрос к типографике )
                  надо будет у дизайнеров поспрашивать
                  • +2
                    Отступ с четырьмя пробелами будет гораздо лучше читаться. Он ещё совпадает размером с var и пробелом — тоже удобно.
                    • 0
                      … и с for с пробелом — внутри цикла ровный отступ
                    • 0
                      Но ведь всегда можно придумать симпатичную альтернативу
                      var foo = 1
                        , bar = 2
                        , baz = 3;
                      
                      • +1
                        Вы это всерьёз назвали симпатичным?
                        • 0
                           
                      • 0
                        Кстати, откуда такой стиль берёт своё начало?
                        Давеча видел такое форматирование у коллеги DBA, потому и удивился.
                        • +1
                          gist.github.com/isaacs/357981 хорошая дискуссия по этому поводу.
                          • 0
                            Спасибо, хорошая ссылка. Наглядно указали на некоторые плюсы и минусы такого стиля (comma-first и dot-first). В этой дискуссии обсуждают только JS, но мне довелось повстречаться в различных проектах с такой нотацией и в других языках. Иногда попадались интересные решения в стилях.

                            Я считаю, что очень важно что бы в проекте стиль был единым, а какой стиль выбран для проекта — не такой важный вопрос. IDE можно настраивать под стили и нотации каждого отдельного проекта, а глаз программиста достаточно легко перестраивается.
                      • 0
                        Не стал бы такое делать в JavaScript из-за автоматической вставки точки с запятой. Уже напоролся на
                        return
                        [], теперь стараюсь заранее указывать языку, что дальше не конец выражения.
  • +2
    Популряный совет «используйте jslint.com» весьма уныл с практической точки зрения. Вы правда думаете что кто-то ходит на регулярной основе на этот сайт и проверяет каждый свой коммит в JS там? Все такие вещи должны а) уметь быть запущенными локально б) прикручены к CI. Исключение может быть только если вы один в команде и делаете два коммита в год в js-файлы.

    На самом деле из совета на эту тему — лучше сделайте npm install jshint Он как минимум «из коробки» куда более лояльный и практически применимый.
    • 0
      Разумеется это должно быть в CI и локально показываться в IDE. Смысл комментария показать инструмент. Кстати настройка и внедрение тянет на еще одну статью.
      Кусок из настроек моего пичарма
      image
    • 0
      в Notepad++ можно линт подключить.
  • 0
    в 18 пункте более «элегантная» форма записи выглядит довольно устрашающе. Тут наверное наоборот лучше полагаться на то что — не стоит писать длинных строк которые затрудняют восприятие кода.
    И в примере выше (тот же 18 пункт) пропущена скобка: «if(object.hasOwnProperty(key)) {».
    • 0
      Ну это на любителя как говорится. У себя в питоне я привык использовать подобные конструкции
      for x in (i in somelist if i > 3):
         ...
      

      PS скобку добавил, спасибо.
      • 0
        И сам порой люблю пугать незнакомы с Питоном программистов конструкциями типа:
        x = [(x) for x in (1,2,3) for y in (3,2,1) if x < y]
        


        Но надо же быть демократичным.
        • 0
          ну это чересчур )
          а вот внести один иф в цикл можно — читается просто и экономит 2 строки.
  • 0
    Давным-давно это не было редкой практикой использования аттрибута language у тега script.


    Атрибут type=«text/javascript» тоже можно смело убирать.
  • +1
    У Ильи Кантора встречается более элегантная форма записи
    for(prop in object) if (object.hasOwnProperty(prop)) {
        //...
    }
    


    но честно говоря я не уверен какие браузеры могут корректно обрабатывать ее.
    Прим. пер.


    Ведь все браузеры корректно могут, это ведь не специфическая конструкция, это просто

    for (var prop in object)
        if (object.hasOwnProperty(prop)) {
            //...
        }
    


    Object.hasOwnProperty есть во всех актуальных браузерах и даже в старых IE (начиная с 5.5).

    На самом деле, казалось бы, всего лишь убран перенос строки, но код уже не кажется таким загроможденным. Вроде бы и просто догадаться, но как-то не думалось, что это на самом деле неплохое решение )
    • –5
      Круто! Спасибо, я думал это отдельная конструкция )
      • 0
        Тем не менее, это противоречит пункту 3
      • 0
        ого… вы не понимаете смысл этих элементарных строк кода?
        • 0
          После 5 лет питона это казалось вполне нормально лексеммой языка.
  • +7
    В названии забыли словосочетание «для начинающих» — в оригинале «24 JavaScript Best Practices for Beginners».

    Статья действительно для начинающих разработчиков. Половина советов в стиле «Капитана Очевидность».

    Но больше всего убил совет №2 «Eval = Bad». Это извращённое и неверное представление об eval.
    Во-первых, eval всего лишь в 4 раза медленнее apply или call, но гораздо быстрее всех остальных методов. При этом замечание глупое, т.к. разности в скорости между методами для конечного пользователя не заметны.
    Во-вторых, eval не угрожает безопасности приложения. Безопасности приложения угрожает отсутствие проверки данных на сервере.
    Из-за этого тупого утверждения «Eval = Bad» большая часть приложений используют воистину извращённые способы выполнения кода на клиенте, но по сути те же eval.
    • +3
      Когда говорят что eval is evil, имеется в виду, что в большинстве случаев он не нужен и поэтому стоит подумать над альтернативными вариантами. Конечно, бывает, что он просто необходим.
      Из-за этого тупого утверждения «Eval = Bad» большая часть приложений используют воистину извращённые способы выполнения кода на клиенте, но по сути те же eval.

      Это лишь признак непонимания разработчиков сути утверждения eval is evil. Так как под eval имеются в виду исполнение стороннего кода вообще, любыми способами.
    • 0
      Eval плох, если в него вставлять пользовательские данные, а если собирать функцию «из кирпичиков» для оптимизации (JIT-компиляции в JS, например), то очень даже полезен. Но лучше не eval тогда, а new Function.
      • 0
        SiPlus, чем лучше?
  • +5
    4. Используйте JS Lint

    Перефразировал бы как «НЕ используйте JS Lint») долго сидел на нем и следовал фанатично всем мелочам. По факту — это того не стоит. Используйте JSHint.

    Отдельно хочется заметить, что многие из приведенных примеров JS Lint бы не прошли)
    • +1
      Точно. Как написал автор этого форка — начиная с версии X js lint заставляет писать не как хорошо, а как автор js lint.
      Запустил, получил кучу ошибок «используйте запись 24 == value» и ещё подобных, удалил, поставил jshint.
  • +4
    спасибо, ностальгия
  • –3
    А еще можно так:

    void function(){
    }();
    • +3
      !function() {
           // …
      }();
      
  • 0
    Оператор „for… in“

    Лучше использовать each-итератор, т.к. код станет более читаемым (не нужно будет использовать hasOwnProperty).
    • 0
      Один известный браузер с вами не согласен.
      • +1
        Все со мной согласны, я говорил не про конкретный each, _.each или $.each вполне под ним работают.
  • 0
    Насчет точек с запятой — регулярно встречаю этот совет от Кроуфорда и прочих, плюс его JSLint на это ругается.

    Я встречал на практике только одну реальную проблему с этим делом — когда между return и значением ставится перенос строки. Обязательная точка с запятой проблему эту не решает. Эта проблема решается повсеместными египетскими скобками.

    Я видел только один пример, где пропущенная точка с запятой может принести проблемы:
    var x = 2
    [1,2,3].map(function() { console.log(x); })

    Может кто еще привести каких-нибудь, поближе к практике?

    Вообще я считаю что тема слишком раздута — я писал и с точками с запятой, и без них, и ни разу не налетал ни на какие проблемы.
    • 0
      Читал, что если загнать код без точек с запятой в Google Closure Compiler например, то могут возникнуть проблемы. Т.е. при минификации/обфускации кода.
      • 0
        Если так — то это проблема оптимизатора, и нужно брать оптимизатор, который умеет работать по стандартам языка. Сильно сомневаюсь, кстати, что таким страдает гугловский оптимизатор.
    • 0
      Я встречал на практике только одну реальную проблему с этим делом — когда между return и значением ставится перенос строки. Обязательная точка с запятой проблему эту не решает. Эта проблема решается повсеместными египетскими скобками.

      Как раз попросили обратить внимание на ASI ссылку на который я добавил.
  • +1
    ===
    6. Объявляйте переменные для вне циклов
    ===
    Не сразу сообразил, к чему там «для» ))
    • 0
      и не «Объявляйте» а «инициализируйте», объявлять их можно где угодно (хоть после return), главное внутри функции.
  • +4
    для тех, кто часто работает с DOM'ом, добавляет что-то на страницу, в цикле например, то используйте

    document.createDocumentFragment()

    добавляйте в цикле в него то что необходимо, и потом уже делайте 1 раз append этого фрагмента куда надо на странице, сэкономите на перерисовке DOM'а
  • 0
    Мне много раз говорили о том что нужно объединять переменные под один var и разделять запятыми. Честно говоря мне кажется не очень наглядно тем неменее становится, экономии ни какой, крутые приложения на js счас принято минифицировать и как следствие все эти var'ы и так пропадут.
  • 0
    Довольно простые советы. Многие подходят и к другим языкам.

    5. Переместите скрипты вниз страницы
    Можно еще аттрибут async добавить.
  • +1
    Используйте комментарии

    // Cycle through array and echo out each name.   
    for(var i = 0, len = array.length; i < len; i++) {  
       console.log(array[i]);  
    }  
    


    Плохой совет. Надо писать код так, чтобы его не надо было комментировать. И уж представить себе совета по поводу комментирования хуже чем капитанить в комментариях к коду выше сложно себе представить
    • +1
      Надо писать код так, чтобы его не надо было комментировать.

      Так обычно говорят после пары лет программирования. Пару серьезных проектов и это пройдет.

      Капитан докладывает что капитанство по коду выше всего-лишь пример.
      • –1
        А можно пример? Лично я не вижу смысла комментировать код, если он качественно написан. Это все равно не даст новой информации. А вот всякие специфичные вещи из отрасли или сложные алгоритмы стоит комментировать, конечно.
        • –1
          font = ImageFont.truetype(self.FONT_FILENAME, int(self.lines_height[len(text)] * 2))
          font_size = font.getsize(text)
          font_img = Image.new('RGBA', font_size, 0)
          
          mask = Image.new('L', font_size, color=255)
          draw = ImageDraw.Draw(mask)
          draw.rectangle((0, 0, font_size[0], font_size[1]), fill=0)
          font_img.putalpha(mask)
          
          draw = ImageDraw.Draw(font_img)
          draw.text((0, 0), text, font=font, fill=self.COLOR) 
          font_img = trim(font_img)
          
          ratio = float(font_img.size[1]) / font_img.size[0]
          height = int(ratio * self.line_width)
          region = font_img.resize([self.line_width, height], Image.ANTIALIAS).crop([0, 0, self.line_width, height])
          lines.append(region)


          Убрал комментарии. Без них выглядит не очень читаемо.
          • +3
            Не лично вам, но все же
            А когда код меняет свою суть, то комментарий не забываете обновлять?

            Конкретно ваш пример прекрасно показывает то, что можно и без комментариев — достаточно лишь добавить немного функций
            createFont() drawRectangle() drawText() extractRegion()

            И все — теперь мы знаем, что делает код. Я скорее всего ошибся с названиями: их можно удлинить бОльшим количеством описания. В одном из проектов вполне можно было встретить что-то типа convertSingleSailInTwoSailsPerDayForMinskRoute()
            • –3
              Т.е. размазать логику по методам класса, при том что она используется только в одном методе? Ну уж увольте. Я лучше комментарии напишу.
              • 0
                Зачем размазывать? Давно придумали замыкания. И когда потом, через полгода, вам вдруг внутри функции, которую вы привели, надо будет изменить реализацию метода — вы сходу его найдете. Все потому, что 1. функции-замкания, которые вы сделали — маленькие, 2. они делают только одну вещь — создают шрифт, рисуют что-то, правят и т.п.

                Я раньше тоже не мог без комментариев. Но попробовав без них в js теперь не могу себя заставить заставить сделать огромную функцию с кучей действий в других языках. Если функция делает две вещи — значит вам нужны две функции :)

                Есть несколько вещей, для которых все еще допустим использовать комментарии с моей точки зрения:
                1. описание зудобробильных регулярок
                2. пометка регрессионных unit-test'ов номером задачи из баг-трекера
                3. Странные действия. Например, в каком-то тесте, в отличии от десятка других, мы проверяем свойства расписания не понедельника, а вторника. Полезно написать, что это сделано потому, что во вторник поезда выбранного направления, например, на мойке :) Хотя, даже это можно инкапсулировать в getTestWeekdayForTrainById(trainId) и туда зашить логику… Хм… Пойду вкоммичу.
                • 0
                  Что такое функции замыкания?
                  • 0
                    автор имел ввиду вложенные функции (которые, кстати, не всегда являются замыканиями)
                  • +1
                    я обычно оформляю подобные вещи таким образом:
                    function main(){
                        //...
                        doSomething();
                        //...
                        
                        return;
                        
                            function doSomething(){
                                //...    
                            }
                    }
                    

                    это облегчает чтение — когда видиш return, сразу становится ясно, что дальше никакого кода не выполнится.
              • +1
                почитайте про рефакторинг. один из основных запашков кода — это длинный метод.
                • 0
                  Расскажите мне еще за фаулера, ага.
            • 0
              Вы считаете, что поменять название функции, если код в ней поменял свою суть никто не забывает и это проще, чем поменять комментарий?
              // Create font
              ...
              // Draw rectangle
              ...
              


              А если подобный код, который продемонстрировал Azy, нужно выполнить в большом количестве итераций? Тут можно слегка сэкономить — не производя лишних вызовов функций (а иногда и в определении функций).
              • 0
                Как показывает практика — за названиями функций следят большем, чем за поясняющими его комментариями. Все-таки название функции — это часть кода, она «читается». А комментарии — это некий «шум»
    • 0
      поддерживаю. капитанские комментарии — зло. потому как часто случается, что код обновили — а комментарии нет.
    • +2
      Пишу сложный большой проект.
      Комментарии в виде API документации (типа JSDoc) хорошая штука (да и решают все таки другую задачу)

      Во всех остальных случаях: хочешь вставить комментарий, значит код написан криво и надо рефакторить.
  • 0
    7. Есть мнение, что + для строк работает сейчас быстрее, вот, например, пруфлинк: jsperf.com/string-concat-methods-test

    А вообще, всем советую свежую книжку Effective JS Дэвида Хермана, очень неплохо объяснены прототипы, например (http://www.amazon.com/gp/product/B00AC1RP14/ref=oh_d__o00_details_o00__i00?ie=UTF8&psc=1)
    • 0
      Только в Хроме. Незначительно ещё в последних версиях Firefox и IE 10. В остальных быстрее join(). На практике лучше ориентироваться на самый быстрый метод в медленных браузерах, чем выбирать между супербыстрыми методами в реактивных.
  • 0
    Автор кода из пункта 7 не подозревает о существовании пустых массивов.
    • 0
      Вы так говорите, как будто с for в том же случае не надо проверять на непустоту. Не о том же речь.
      • 0
        Не надо. Зачем? Вариант с for'ом тем и хорош, что там всё естественным образом получается без дополнительных проверок, а вот вариант с join или будет производить неожидаемый результат, или будет нечитаемым (для инетерса попробуйте реализовать его таким образом, чтобы в случае нуля элементов возвращался пустой ul)

        Не о том же речь.


        Речь о том, что автор говорит, что for можно заменить функциями для работы с массивами и сам же приводит пример, который не будет эквивалентен коду с for'ом.

        Как по мне, так яблоки нужно сравнивать с яблоками.
        • +1
          А, вот вы о чем, понял. Все же чаще нужно, чтобы при пустом массиве не было ul вообще.
  • 0
    18. Оператор „for… in“
    При проходе в цикле через свойстав обьекта вы также обнаружите что получаете в том числе и функции. Для избежания этого необходима проверка с if hasOwnProperty

    Вы (автор или переводчик) о чем здесь вообще?
    Я аж с перепугу перепроверил

    var o = {a:1, f:function(){}}
    for(var key in o) 
      if(o.hasOwnProperty(key)) console.log(key)
    //a
    //f
    
    • +1
      Автор вырезал текст из контекста, а переводчик наверное вчера только JavaScript начал изучать, толком не понимает еще о чем пишет )))
      Но пост тем временем в плюсе. Эх… хабр уже не торт…
      • 0
        Переводчик написал свой комментарий, по поводу hasOwnProperty
        Вообще Object.prototype.hasOwnProperty проверяет принадлежит ли свойство непосредственно обьекту а не его цепочке прототипов. Подробнее можно почитать в JavaScript Garden
        У Ильи Кантора встречается более элегантная форма записи
        • 0
          это хорошо. но тем не менее ошибку автора вы скопировали и не исправили
      • +1
        И пишите свои посты, чтобы «был торт»
        • 0
          уже в процессе :)
    • 0
      Имелись в в виду функции прототипов.
      • 0
        В любом случае „for… in“ перебирает не только функции методы прототипов, но все их свойства.
        • 0
          В любом случае я это знаю. Спасибо.
    • 0
      и вообще, если ваш объект приходится часто листать, то лучше установить его свойства с помощью defineProperty, чтоб ненужные свойства были not-enumerable
  • 0
    Удалил
  • –2
    Можно кратко почитать статью, а можно просто почитать две полезные книги (вне зависимости от того, пишешь код на JavaScript, TypeScript или JavaScript) — Javascript: Good Parts и Javascript: Templates. (=
  • 0
    Воспользуйтесь прогрессивным улучшением (progressive enchantment)

    Шутка, или опечатка по Фрейду? Мне понравилось ;)
  • 0
    Ещё по теме — Airbnb JavaScript Style Guide. Не думаю, что я полностью согласен со всеми пунктами, изложенными там, но в любом случае материал полезный и по текущей теме.

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