Pull to refresh

Comments 189

Однозначно нужно продолжить начинание!
Сам вот начинал прям как у вас всё расписано! Новичкам must read!
must read — мало, надо must to understand && must to use
новчики must die, а те кто выжил — пусть кодят.
Ещё раз убеждаюсь, что перед использованием jQuery неплохо бы javascript поучить. Был абсолютно таким же велосипедистом на jQuery, пока вдруг не осознал, что javascript куда шире. Сейчас мне куда приятие писать xhr = new xmlHttpRequest(), вместо $.ajax({...}).
UFO just landed and posted this here
Вы меня не поняли. Возможность писать на plain javascript — это действительно великолепно, после одного лишь jQuery. Но jQuery это уже вполне сформировавшийся стандарт, на котором люди ведут разработку, в том числе и я. И от этого плюсов больше, чем минусов (ИМХО).

Минусующим:
На примере того же ajax. Комментарием выше я имел ввиду то, что знать как работает ajax изнутри очень помогает не наступать на грабли, описанные в статье.
ваш велосипед

xhr = new xmlHttpRequest(), вместо $.ajax({...}).


не будет работать в младших версиях IE — там использовался ActiveX.
И что с того, этих младших IE 5-6 уже меньше процента. А начиная с IE7 уже был xmlHttpRequest.
У меня была беда. Сделали сайт (медицинский).
И оказалось, что среди частых посетителей пару людей, ИЕ6.
Пришлось выкинуть массу аяксовых вещей, точнее переписать вообще весь фореграунд.

Уверены, что это реальные юзеры? У меня в логах ежедневно отмечаются IE 2.0d, IE 3.02, IE 4.01.
Ну, 4.01 — это Pocket PC/Windows CE.
Да я не спорю, только с таким юзерагентом, ходят исключительно боты, которые пытаются отправлять рекламу с помощью обратной связи :)
А в младших версиях Netscape вообще ничего работать не будет, вот ужас.
Поддержки Netscape у меня в ТЗ не указанно. Странно, да?
Ок, а если я напишу так:
function get_xmlHttp(){ 
	var xmlHttp; 
	try{ 
              xmlHttp = new XMLHttpRequest(); 
	}
	catch(e){ 
		var XmlHttpVersions = new Array("MSXML2.XMLHTTP.6.0", 
		"MSXML2.XMLHTTP.5.0", 
		"MSXML2.XMLHTTP.4.0", 
		"MSXML2.XMLHTTP.3.0", 
		"MSXML2.XMLHTTP", 
		"Microsoft.XMLHTTP"); 
		for (var i = 0; i < XmlHttpVersions.length && ! xmlHttp; i ++ ){ 
			try{ 
				xmlHttp = new ActiveXObject(XmlHttpVersions[i]); 
			} 
			catch (e){ 
			} 
		} 
	} 
	if( ! xmlHttp) 
	     //errorHandler 
	else 
	     return xmlHttp; 
}


вы поймёте, что я утрировал?
И вы считаете что вышеуказанный код реально лучше, чем использовать $.ajax({...})?
Если писать кроссбраузерный userJS — да. При написании расширений к браузерам очень помогает умение пользоваться чистым JS, потому как там не приветствуется подгрузка дополнительных скриптов.
На счет того, что нужно уметь пользоваться чистым JS я полностью согласен. Но здесь тема про велосипеды.

Как по мне оправданность создания своей библиотеки для ajax есть, только если ничего другого из всего многообразия функций jQuery использоваться не будет. Но по факту, обычно на проектах используются и другие функции, хендлеры и т.д. И писать самому либы, которые будут повторять функционал jQuery не вижу смысла(к тому же процентов 99.9%, что самописные либы лучше, кроссбраузернее и быстрее работать не будут).
Зависит от конкретной задачи. Это был ответ пользователю DsXack, который думает, что я действительно так пишу на реальных проектах. Отвечаю: Нет я использую jQuery.ajax, new Ajax.Request, Ext.Ajax.request и прочее. При этом написав тот пресловутый «xhr = new xmlHttpRequest()» я имел ввиду, что знать как все эти обёртки работают крайне важно для человека пишущего на javascript.
С вашим мнением по поводу знания чистого JavaScript я согласен. Был несогласен лишь с тем кодом, написали бы хоть, что это антишаблон, а то… статья для ведь для начинающих. JavaScript пока что вообще стал моим любимым языком, я полюбил прототипы.
А мне вот пофиг как это работает. В смысле, как оно реализовано.

Если северный зверёк начнёт плакаться за производительность, вот тогда я и полезу вглубь.

Хотя с другой стороны так и не проникся рельсами поскольку там полно неочевидной магии. А jquery — магичен ровно настолько, чтобы не было мучительно сладко, но и не приходилось добывать сахар самому, притом из семян (даже не корнеплодов) сахарной свёклы.
на js можно очень легко написать говнокод, который будет очень непроизводителен, как минимум. поэтому на веб-языки и гонят.
динамическое навешивание обработчиков появилось изрядно раньше в v1.3, через метод «.live», впоследствии замененный на чуть более удобный «.on».
Да, забыл об этом упомянуть. А также еще есть метод «.delegate"», который работает почти, как и live, только явно указывается узел, на который навешивается обработчик.

Но и .live и .delegate с версии 1.7 deprecated
Приятно видеть ссылки в комментариях :visited )
На мой взгляд гораздо лучше использовать data-* параметры, например
<div class="comment" data-id="123"></div>


На мой взгляд лучше использовать plain js: domObj.id или $jqueryObj[0].id
У вас при таком использовании на странице id ни разу не совпадали?
а я использую вместо идентификаторов классы. проблема уникальности отпала за ненадобностью.
произвольные аттрибуты мне доверия не внушают.
Классы всё же для css создавались. Мне вот лично уже не приятно смотреть на div у которого стопицот классов, которые никак не относятся к оформлению. Если указывать id или же data-*, то читаемость значительно повышается.
Стопицот классов, не относящихся к оформлению — это уже что-то не так с проектированием.
Кстати, наоборот, появляется возможность оформлять элементы по какому-то признаку.
Эммм, по-типу
.user-1:before { content: "Привет одмин" }
?
Ну как бы само собой разумеется. Пост для слишком уж начинающих.
Хабрасообщество не может определиться хороший пост или он для начинающих? :)
Это хороший пост для начинающих.
Хабр вообще в целом для начинающих хорош.
Если они ничего не пишут, а только читают ;)
Я не слишком начинающий, но для меня интересно было почитать пост. Вот.
Полезная заметка)

Обычно статьи про jquery здесь удручают, но не эта) Надеюсь, продолжение следует.
Очень как-то за уши притянуто. Соглашусь, всегда лучше использовать изящные решения. Но велосипедами такие моменты не назвать. Можно использовать библиотеку по-разному, и в первую очередь используются самые простые варианты, которые позволяют быстро решить задачу, а уже потом рефакторинг.
А говорить что $post плох тем, что у него есть последним параметром можно передать dataType это как-то уж совсем перебор. Можно посоветовать описывать обработчики в отдельном месте со всеми простынями кода. Тогда это не будет такой проблемой, например.
Вы перевираете автора. Он не говорил что $post плох. Он говорил что ему больше нравится ajax, и привел свои аргументы. Это то же самое как вопрос о переносе открывающей фигурной скобки — кто то переносит, а кто то нет.
Согласен. Ничего не мешает, для повышения читаемости кода писать
var callback = function() {//много страниц}
$.post(url, data, callback, 'json');
> и в первую очередь используются самые простые варианты, которые позволяют быстро решить задачу, а уже потом рефакторинг.

Главное что бы время рефакторинга наступило хоть когда-нибудь :(
такого не бывает :)
Самое постоянное — это временное
По поводу post, я не согласен. Во первых все функции возвращают deffered object, у которых есть есть методы done,complete,fail(а error является устаревшим). Тип преходящих данных нужно указывать на стороне сервера отправляя правильный заголовок content-type:application/json jQuery cам поймет, как с ним работать(читаем документацию:The type of data that you're expecting back from the server. If none is specified, jQuery will try to infer it based on the MIME type of the response (an XML MIME type will yield XML, in 1.4 JSON will yield a JavaScript object, in 1.4 script will execute the script, and anything else will be returned as a string). ). Поэтому писать обработчик в sucess, не очень хорошо.
> а error является устаревшим
ссылку можно?

>«Поэтому писать обработчик в sucess, не очень хорошо».

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

Прошу прощение, по поводу метода comlete написал по старинке. А вот цитата из документации:Deprecation Notice: The jqXHR.success(), jqXHR.error(), and jqXHR.complete() callbacks will be deprecated in jQuery 1.8. To prepare your code for their eventual removal, use jqXHR.done(), jqXHR.fail(), and jqXHR.always() instead.
По поводу метода success, действительно как-то не понятно получилось. Суть в том. что лучше все таки использовать $.ajax, Как deffered object. И писать код вроде следующего:
$.when($.ajax(...)).done(...).fail(....).always(...)
Да, jqXHR.success(), jqXHR.error(), and jqXHR.complete() deprecated будут, но в параметрах для $.ajax() по прежнему будет указываться success.
Даже открыв ajax.js в master ветке на github и взглянув на 236 строку можно увидеть success: callback
А я и не говорил, что success будет deprecated. Я говорю, о том, что лучше его использовать $.Deferred, это даст куда более читабельный код. К примеру код:
var cache = [];
function getData(id) {
  return cache[id]||$.post('/ajax/',{id:id}).done(function(data){
    cache[id] = data;
  });
}
function useData() { 
  $.when(getData(1)).done(function(){
    console.log(data);
  });
}
useData();

Это просто один из примеров, примянять можно по разному.
А вот по поводу, если на сервере произошла ошибка, то что вы укажете определенный тип возвращаемых данных, вам не поможет, все равно задействуете медот fail.
Но если задать не верный content-type, то часто отладчики вроде developer tool или firebug, во вкладке json отобразят, не то что вы ожидали увидеть. А ведь отлаживать, приходиться часто, и хорошо, если код писали Вы, а не кто-то другой и ответ верный вам не известен.
Не совсем так. сравните два примера (прямо на странице хабра выполните в консоли). они отработают по-разному.
$.get('/', function(data){console.log(data.a.b)});
$.get('/', function(data){console.log(data.a.b)}, 'json');

указание dataType в этом случае как раз и обеспечит вызов fail а не success
Здесь я с вами соглашусь, но, если Вы настроите, что по определенным url, сервер отдавал content-type:application/json, то тоже будет fail. Я, на самом деле, сразу использую конструкцию
$.ajaxSetup({
    dataType:'json'
});

Так как, другие типы ответа редко использую.
А если сервер ответил белибердой вместо json, тоже будет success? Мало ли что.
Не совсем понял про $.post и $.ajax

С остальным согласен. Особенно про Неймспейсы и data-*
Только вопрос читабельности при использовании dataType. Никаких идеологических претензий к $.post нет
UFO just landed and posted this here
UFO just landed and posted this here
UFO just landed and posted this here
UFO just landed and posted this here
> например, у него мне в первый раз встретилось слово «читабельный», «читабельны»
UFO just landed and posted this here
Опровержение чего? опровержение чьего-то мнения? Если я впервые узнал что такое «html» от учителя информатики, то это вовсе не значит что учитель информатики придумал это слово.

Я думаю не стоит обсуждать русский язык в комментариях, для этого можно использовать личные сообщения.
и да, я знаю что html это не слово, а абрревиатура. это просто пример
UFO just landed and posted this here
ММмммм… А все остальные слова, которые вы используете, они не искусственно придуманы, а дарованы свыше, силами небесными?))
UFO just landed and posted this here
Могу посоветовать не нести чушь. А то так скатимся до языка Мицгола.
Около четверти слов, которые вы используете в повседневной жизни, появились в 20м веке, были позаимствованы или придуманы.
Это язык, он живет и развивается. И обсуждаемое слово вошло в оборотную речь задолго до вашего и моего рождения.
UFO just landed and posted this here
Имхо, «читаемость» — «принципиальная (физическая) возможность прочитать», «читабельность» — «возможность удобного чтения».
Ну да, json в конце вызова метода теряется, а иногда просто забывается.
Небольшое дополнение, если на проекте вы используете jQuery UI. То в нем уже зашиты многие константы кодов клавиш в объекте $.ui.keyCode. Тут не стоит забывать, что если пишете какой-то плагин и соберитесь выкладывать в сообщество, нужно подумать, следует использовать или определить свои константы.
UFO just landed and posted this here
Но рассмотривать готовые решение надо всегда. Хотябы для того, чтоб посмотреть, как эту задачу пытались решить другие. А потом, если она не популярна и в ней чего-то не хватает, то можно допилить либо написать свою, включив в нее самые лучшие идеи из готовых.
UFO just landed and posted this here
Правильное слово тут «Антипаттерн» вместо «Велосипед», если я не ошибаюсь. Велосипедов в статье, собственно, ровно один – это обращение к замусоренным атрибутам – и тот крохотный.
Из антипаттернов часто ещё можно встретить бесконечное дёргание одного и того же хендлера или как его назвать.
$( '#one_long_selector' ).someAction();
...
$( '#one_long_selector' ).getSomeAttribute();
...
$( '#one_long_selector' ).writeSomeValue( value );


Правильное, на мой взгляд:
var _handler = $( '#one_long_selector' );
_handler.someAction();
...
_handler.getSomeAttribute();
...
_handler.writeSomeValue( value );

Во-первых, это экономит ресурсы системы по поиску нужного элемента в DOM. Ищется он теперь один раз вместо трёх. Во-вторых, мне такой код проще читать и менять, если что случилось.
Что мешает написать $( '#one_long_selector' ).someAction().getSomeAttribute().writeSomeValue( value );?
Например, потому что каждый из них может быть вызван при каком-либо условии или внутри функции.
Троеточия мешают :) Они предполагают наличие ещё какого-либо кода.
Если мне память не изменяет, искать будет один раз, остальные два хендлер будет подставлен из кэша.
Эвона как. А не поделитесь ссылочкой на какой-нибудь материал, насколько вообще на самом деле прожорливы подобные вызовы, как устроен этот кеш (что будет, если какое-либо свойство элемента поменялось, минуя Jquery) и всё такое?
Вот, например: jsperf.com/caching-jquery-selectors

Если в DOM что-либо менялось минуя jQuery, то кешированные в переменные объекты с селекторов придется тоже как-то обновлять. Это вообще болезненная тема и собственно само по себе кеширование тут имеет мало непосредственного отношения.
я начинающий jquery-ст, и есть вопрос по теме:
есть $('...').click() и $('...').on('click', function() для в том числе создающихся элементов на странице.
Можно ли использовать второй вариант вместо первого и есть ли подводные еще, кроме падения производительности, описанной в статье?
Второй вариант вместо первого, начиная с jq 1.7 рекоммендуется использовать, только то что вы написали — ничем не отличается друг от друга., нужно:
$('#some_container').on('click', '.dynamic_child_elements', function(){})
В документации очень доходчиво написано.
И полезно: jqapi.com
ой, я конечно ошибся. имел в виду например $(document).on('click','...', function(){});
Сейчас, у меня на подходе, как раз статья на эту тему. Отвечу, что приведенные, вами сигнатуры являются синонимами, поэтому даже падения производительности не будет. Приведенный вами пример, как раз относится, кому как удобно и где как удобно. Но к примеру, если вы будете использовать второй пример, вам будет проще в будущем, сделать делегирование событий(меньше строчек кода писать придется). Поэтому, если вы хотите что бы события слушались на новых элементах, вам следует применять прием, который приведен в статье. А если вы сделаете $('...').click() и $('...').on('click', function(), то события на новых элементах не будет обрабатываться. Вот пример learn.javascript.ru/play/qyQ3kb.
ой, я конечно ошибся. имел в виду например $(document).on('click','...', function(){});
Биндер событий «on» хороший, но отнюдь не факт, что он всегда эффективнее по производтельности.

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

Вешать on на body можно только в RIA, и то не всегда. В остальных случаях — его контейнер нужно максимально «углублять» (т.е. брать на столько глубокий элемент, на сколько можно)
Про Namespaced events:
на event можно навешивать функцию (не анонимную) и тогда её можно будет затем анбиндить явно.
Namespaced events также дают возможность делать trigger определенных событий $(elem).trigger('click.namespace1') позволит вызвать только обработчики из namespace1. В случае плагинов это весьма полезно
Статья очень понравилась, я бы хотела внести предложение. Напишите, пожалуйста, статью про особенности использования JQuery/javascript в плагинах. Я подозреваю, что там их много. Сама пишу плагин впервые. Очень много вопросов и подчас даже непонятно как их задать. Трачу много времени.
Как раз думал об этом. Главное найти время и силы для этого. На какие то конкретные вопросы по плагинам могу ответить в ЛС
Для клавиатурных содытий есть новый стандарт DOM Events Level 3, который определяет свойства key и char.

document.addEventListener('keyup', function(e) {
  if(e.key == 'Esc' || e.key == 'Enter') { }
})

Попробовать на вкус можно тут.

А константы Event.DOM_VK_* есть в некоторых браузерах (сейчас нету возможности посмотреть, но, по-моему, в FF есть) и были определены предыдущей редакцией стандарта и уже успели устареть
а если в какой то момент нам захотелось
изменить метод с GET на POST?
Ага, затем ещё добавить $.putJSON(), $.patchJSON() и $.deleteJSON().
Мне кажется плодить функции, которые функционально ничем не отличаются, кроме изменения 1-2 параметров, как-то не очень правильно…
а если в какой то момент нам захотелось изменить метод с GET на POST?
Тогда мы ничего не сможем сделать и мир погибнет.
$.ajax({
    type: "GET" //
    ...
})
Ой, type: «POST»
Весь сарказм запорол…
Часто бывает необходимость добавить обработчики событий к элементам страницы (например, кнопка «удалить сообщение»). И зачастую можно встретить подобный подход:

$('.comment a.delete').click(function(){
//
});

Минусы этого подхода — в памяти создаются N абсолютно одинаковых обработчиков, поэтому если на странице 1000 комментариев — потребление памяти будет существенным.


А что мешает вот так написать:
var deleteCallback = function () { ... }
$('.comment a.delete').click(deleteCallback);

???
Так же будет создано большое количество обработчиков, ведь к каждой a.delete привяжется обработчик, а в случае с .on — он будет один, на body.
Прошу прощения — ошибся немного в описании, а точнее в примере. на самом деле если написать так
$('.comment a.delete').click(function(){...});

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

а если написать вот так
$('.comment a.delete').each(function(){
    $(this).click(function(){...});
});

то тогда будет N обработчиков в памяти.
К сожалению второй вариант тоже попадался мне на глаза на практике.

Ваш вариант безусловно решает эту проблему. Поправлю статью с этими примерами и добавлю вариант решения с вынесением обработчика
А нет, все таки создаются копии в обоих примерах, а также в вашем варианте. Изначально я был прав
Проверить можно так:
var handler = function(e) {
    e.preventDefault();
    this.a = (this.a || 0) + 1;
    console.log(this.a);
}
$('a').unbind('click').click(handler);

Теперь если сначала по каждой ссылке будет выводиться свой счетчик
Пардон, не выспался, this здесь другой смысл имеет. конец недели дает о себе знать)
Спасибище огромное! Постоянно наступаю на все грабли какие есть в JS. Буду благодарна еще материалам по этой же тематике.
Мои 5 копеек.

2. Бытует мнение что лучше вместо selector.data использовать $.data
jsperf.com/jquery-data-vs-jqueryselection-data

Есть небольшой неочевидный косяк с этим способом, нужно передавать DOM элемента, а не объект jQuery, поэтому ваш пример можно переписать так:
var id = $.data(this, 'id');
Я предполагаю что this возвращает DOM элемент, но если вдруг у вас собственный селектор, то, вероятнее всего нужно будет получить из него DOM элемент, вот так, например:
$('.my_class')[0]


4. Маленькая неточность, лучше не использовать «тяжелые» селекторы
24ways.org/2011/your-jquery-now-with-less-suck

Ваш пример лучше записать так:
$('body').find('a').on('click', '.external', function(e) {
    //функция будет вызвана при клике на любую ссылку с классом external
});
>Ваш пример лучше записать так:
$('body').find('a').on('click', '.external', function(e) {
//функция будет вызвана при клике на любую ссылку с классом external
});
Не вводите людей в заблуждение, функция будет вызвана только на тех элементах, которые существуют на странице. Если добавиться новый элемент, то обработчик не сработает.

Почему сразу «вводить в заблуждение»?

Конкретно этот пример относился к ситуации, когда нужно было навесить обработчик на удаление комментария. Если представить абстрактный шаблон портянки комментариев:
<div class="b-comments">
  <div class="b-comment">
    <button class="b-delete" title="Удалить комментарий">Удалить</button>
  </div>
  <div class="b-comment">
    <button class="b-delete" title="Удалить комментарий">Удалить</button>
  </div>
  <div class="b-comment">
    <button class="b-delete" title="Удалить комментарий">Удалить</button>
  </div>
</div>

Навешиваем:
$('body').find('.b-comments').on('click', '.b-delete', function(e) {
    //функция будет вызвана при клике на любую ссылку с классом external
});
Пример который вы привели, отличается от того первоначального. Замете, что блок .b-comments не будет больше добавляется на странице. В отличии от тега a.
Конечно отличается, я лишь подметил что делать медленные селекторы — не лучшая практика.
Какая религия мешает вместо $('body').find('a') написать просто $('a')?
Приятно читать то, о чём хоть немного знаешь, но взгляд уже «зашоренный». Ждём продолжения.
Стоит еще момент уточнить насчет:

$('body').on('mousemove', selector, function() {
//
});

А то щас все новички будут пользовать только его и будут считать что это правильно.
Есть два способа повесить обработчик на «selector»

Первый:

$('body').on('mousemove', selector, function() {
//
});

Второй:

$(selector).on('mousemove', function() {
//
});

Разница между ними заключается в том, что в первом варианте событие вешается на самом деле на «body», и когда оно срабатывает то жквери прибегает по всем детям body (body это, кстати, не догма, может быть любой другой элемент родителем которого является наш selector) и вызывает наш обработчик для элементов которые соответствую selector и который попали под нужное событие, именно по этому этот обработчик срабатывает даже для новых элементов.
Второй же вариант вешает событие непосредственно на сами элементы.
Соответственно у обоих методов есть плюсы и минусы, которые достаточно очевидны.
Что за магическое число 27?
Написано же черным по белому

e.keyCode == 27


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

На мой взгляд гораздо лучше использовать data-* параметры
Лучше то лучше, но искать его нужно по всему дереву. На мелких страничках все хорошо, но как только тегов становится десять тысяч, производительность будет плачевной.
Зачем учить, если можно так?
e.keyCode === ESC_KEY
Никто не спорит, что можно. Но вот доработки вы на более низкоквалифицированный персонал переложить уже не сможете. Потому что у него будет вопрос, а почему ESC_KEY = 27?

Если в компании существует стандарт, по которому константы записываются в верхнем регистре, следовательно персонал с ними ознакомлен, и вопросов не возникнет.
Нет, почему 27? Откуда число? С какого потолка оно было взято?
Думаете e.keyCode === 27 проще чем e.keyCode === ESC_KEY для понимания в плане понимания «почему 27? с какого потолка?»
e.keyCode == КЛАВИША_СПАСЕНИЯ

а вообще, это вопрос комментирования
e.keyCode == 27 //ESC

так проще, если встречается 1-2 раза
Не проще, но однозначнее. Прямое сравнение с числом не требует перепроверки, а где же в коде появилась магическая константа и не переопределит ли ее кто-то.
1. Да ну? ну назовите мне сходу коды tab, space, shift, backspace, тильды
2. я не говорю про искать по [data-id=...]. Я говорю про извлечение идентификатора
<a href="#" data-id="123" class="delete">Удалить</a>

$('a.delete').on('click', function() {
    var elem_id = $(this).attr('data-id');
    // отправить ajax запрос с id = elem_id
});
1. tab — 8 (точно не помню), space — 32, shift с левой и правой стороны имеют свой код, но в JS его ловим через отдельный флаг, backspace — 9, тильду не использовал, не помню.
2. Понял
Меня что-то беспокоило, когда я это писал, и теперь я понял что, таки перепутал коды. Давно не использовал, забывается информация.
А стал бы такой вопрос ещё через некоторое время и, вероятно, даже бы уже не беспокоило — увидев if (e.keyCode == 8) вы бы решили, что это Tab без всяких сомнений. Или даже пускай сомнения возникли бы, но минутку бы потеряли на поиск нужной инфы, чтобы развеять сомнения.

В общем не считаю, что коды клавиш, номера функций и тому подобная инфа должна быть в коде напрямую литералами в местах использования. Даже когда на ассемблере под DOS писал, то коды функций DOS, BIOS и клавиш «оборачивал» в константы и перетаскивал файлик из проекта в проект, постепенно его расширяя — код типа

mov ah, DOS_GET_KEY
int 21h

выглядит читабельней чем
mov ah, 1
int 21h

особенно если какая-то редко используемая функция.
Что и требовалось доказать. tab и backspace перепутали (tab — 9, backspace — 8). Поэтому и говорю что нужно использовать константы, сравните и скажите что читабельнее:

if (e.keyCode == 8)

или
if (e.keyCode == KEY_BACKSPACE)
Большинство людей даже и этого не знают. И не узнают никогда, если писать
if (e.keyCode == KEY_BACKSPACE)


А является ли им эта информация необходимой?
Она стимулирует изучение смежных областей и лишней точно не будет. Чем больше кругозор программиста, тем более глубоким будет его анализ
Прочитать для справки, чтобы иметь представление о механизмах работы смежных слоев среды — полезно, да. Держать это в «оперативной» памяти — излишне, имхо. При написании кода заглянуть в справочник, чтобы задать подобные константы, а при чтении читать уже мнемонические имена — вполне нормальная практика. Главное понимать, что возвращает e.keyCode (например, код нажатой клавиши или код символа) и откуда его берёт, но знать все возможные значения — излишне. Осядет что в памяти при постоянной работе — хорошо, нет — ну и ладно, особого спада производительности работы программиста это не даст. Пример несколькими уровнями ниже — машкоды и ассемблер. Нужно ли при разработке на ассемблере знать во что конкретно транслируется команда mov ax,0 и в каком бите она будет отличаться от mov bx,0? Может оказаться полезным, имхо, но знать так, чтобы посреди ночи от зубов отскакивало — излишне почти для всех.
Ну, кому как. Мне в работе помогают даже те области, которые слабо связаны с разработкой ПО.

Писать коды вместо литералов считаю сродни кода без комментариев. Хорошо стимулирует приводить все в порядок.
Писать коды вместо литералов

Не понял фразу. Для меня это синонимы.
1. По моему вы преувеличиваете. Часто работаю с клавишами в javascript, для себя давно выработал привычку вбивать в консоль:

document.body.onkeydown = function(e){
    console.log(e)
}


До сих пор никаких проблем. А на счёт читаемости, она тут не нужна. Код
if (e.keyCode == 8)

отрабатывает на столько надёжно, что туда даже лезть не надо и читать. А то, что внутри условия, по ошибке найти не сложно.

2. А вот извлечение айдишника, это вообще больная тема. Этим страдают очень много разработчиков. Тут я с Вами согласен на все 100
на столько надёжно, что туда даже лезть не надо и читать.

Иногда нужно не только баги править, но изменять, поддерживать, тестировать и документировать код.
и вы начинаете судорожно щелкать по всем клавишам пока не увидите в консоли нужное число? По-моему это пустая (а главное — не нужная) трата времени.
и как вы будете искать например что же за клавиша с кодом 103, например на MacBook air? (подсказка — это numpad 7)

Представьте что вы пришли на новое место работы и перед вами задача — нужно чтобы при нажатии на клавишу TAB происходило такое же действие как и при нажатии BACKSPACE. у вас 1000 js файлов. и в каком то из них есть обработчик нужный. как вы будете искать его? Введете в поиск число 8?
Вот тут вы преувеличивайте преувеличенное. Я серьёзно.
>и как вы будете искать например что же за клавиша с кодом 103, например на MacBook air?
Если Вы не знаете, что делает эта клавиша — она Вам не нужна.
Если Вы знаете, найти не сложно.

>нужно чтобы при нажатии на клавишу TAB
В IDE делаю поиск по слову .onkey, и ищу код 9. Это на самом деле очень быстро. А если таких обработчиков туево много, то констата TAB вам точно не поможет. Только профилировщик.

>у вас 1000 js файлов
ИЕ Вас ненавидит, это я так к слову, понимаю, что это пример.
1. Вы в команде что-нибудь когда-нибудь разрабатывали? Уточню — вам хоть раз приходилось разбираться в коде, который писало более 10 разработчиков? Еще раз повторюсь — помимо создания приложений есть еще понятие «поддержка» кода.

Как в таком коде разбираться?
elem.on(keydown, function(e){
    switch (e.keyCode) {
         case 53:
                  apple();
             break;
         case 66:
                  deleteComment();
             break;
         case 22:
                  banUser();
             break;
    }
})


2.
> В IDE делаю поиск по слову .onkey, и ищу код 9.

e.on('keydown', function() {})
e.on('keypress', function() {})
e.on('keyup, function() {})

Боюсь вы не найдете…
>который писало более 10 разработчиков?
Да, и гораздо больше людей. По сей день работаю.

>Как в таком коде разбираться, поддерживать?
Да вполне, пока инет усыпан такими примерами — в этом требуется разбираться.
Разберем ситуацию:
Вам нужно добавить ещё один обработчик клавиши. Сложно? Вроде как нет.
Вам нужно удалить обработчик, вы уже нашли этот код — удалить проще.

Вам захотелось узнать, какие клавиши вообще обрабатываются в проекте — у Вас очень много времени.

>Боюсь вы не найдете…
Да куда я денусь? конечно найду, используя ум и смекалку — иначе эта работа была бы не для меня. Я не вижу смысла таскать с собой на продакшн файлик с кейкодами, чтоб на 10 секунд быстрее разрабатывать.

P.S. Пришли вы на новую работу, а там коды О_О.

Все разработчики разных уровней — кому то на эту задачу нужно 10 секунд, а кому-то понадобится полдня. Использование говорящих названий позволяет уменьшить время разработки в разы. Ни в одном хорошем проекте вы не увидите нигде вшитых чисел в код. Они будут так или иначе вынесены в константы.

P.S. Я надеюсь вы переменные не называете a, b, c? это ведь быстрее, чем набирать userId, да и тягать лишние 5 байт — это же ужас *sarcasm*
Иногда стоит пожертвовать читабельностью в пользу минимализации ошибок. Константы в JS обязательно нужно повторно тестировать, потому что в языке нет такого понятия, как константы (JS 1.8 в рассчет не берем). И, с ростом числа разработчиков, и особенно низкоуровневых, «константы» могут стать причиной сложных в отладке ошибок.
> Ни в одном хорошем проекте
Я считаю хабр, хорошим проектом (загляните в файлик shortcuts.js)
Они даже не обламываются комментарии в коде оставлять в продакшене.

>Я надеюсь вы переменные
Минификатор так делает, а я не на столько хардкорный программист, чтоб так себя и людей в команде насиловать.

Всё, что я хотел сказать — что кодам есть право на жизнь и это не говнокод, в который страшно смотреть.

Ниже s0rr0w ответил про тестирование и жертву читабельности — я считаю аналогично.
Если к кодам есть комментарии и при изменении числовых значений не забывают обновлять комментарии — то я не против (в shortcuts.js кстати они есть).

Но речь не только о кодах клавиш, а об использовании различных чисел без вынесения в константы (особенно если одно и то же число используется несколько раз).
тогда получить идентификатор будет очень просто:

var id = $(this).attr('data-id')


Один косяк — ссылку на элемент по этому data-id будет получить дорого, так как селекторы по id работают намного быстрее
Кто-нибудь исследовал поддержку браузерами произвольных атрибутов data-*?
Аттрибуты понимают все, только доступ через удобный интерфейс element.dataset есть не у каждого.
В пункте 4
Решение: в jQuery 1.7 есть метод on, который привязывает обработчики события, фильтруя элементы по селектору.

В пункте 5
Несмотря на то, что namespaced events были добавлены в jQuery 1.2 — ими мало кто пользуется (Мне кажется большинство людей просто не знают о них).

И в этом же пункте используете метод on, который появится только в 1.7
и? я лишь акцентировал внимание на то, что namespaced events давно существуют в jquery.
и привел пример их использования, а поскольку сейчас актуальная версия 1.7.2, то использован был рекомендуемый метод on (вместо bind).
В качестве альтернативы «Namespaced events» можно выносить функции обратного вызова в переменные и биндить их уже этими переменными. Тогда они также легко снимаются.

Пример прямо из мана api.jquery.com/unbind/

var handler = function() {
alert('The quick brown fox jumps over the lazy dog.');
};
$('#foo').bind('click', handler);
$('#foo').unbind('click', handler);
теперь начну использовать 'json' параметр в $.post() © ваш слоупок
Всё оно, конечно, так, но уж как-то слишком критично.
Многие примеры не так уж и страшны. Попахивает перфекционизмом:)
P.S.: вместо namespaced events можно в unbind передавать ссылку на функцию (через namespace, правда, удобнее).
Полезная штука, узнаю плюхи, на которые сам наткнулcя. Спасибо автору.
Есть вопрос.
pastebin.com/uhZT0RR0
Как в случае ajax запросов передавать в callback переменную n, которая участвовала в формировании ajax запроса?
В этом примере в случае больших пингов нельзя просто использовать переменную, так как при запросе с n=1 в этом случае выведется n=3 + data. Приходится в json ответе дублировать эту переменную, то есть передавать контекст запроса через ответ. Это конечно правильно, но может есть возможность не гонять лишний трафик? Добавление контекста (n) в конце function(data) возвращает n вместо data.
Например, можно воспользоваться self-inoking функцией:
for (var n=1; n <= 3; n++){
    (function(n){
        setTimeout(function(){console.log(n)}, n * 300)//или в вашем случае $.get
    })(n)
}
keltanas предложил ещё один вариант с использованием proxy — gist.github.com/3342168/3358a51efdedf8d8dfacbb555ca0c4197cb62434

Какой вариант предпочтительней, меньше ест памяти и более производительный?

Согласен, оба способа разработчики jQuery должны были указать на странице документации про ajax/get, но там почему-то этого нет даже в комментариях.
Данный вариант не работает:
for ( n=1; n<=3; n++ ){
    $.get( '/', $.proxy( function( n, data ){
        console.log(n);
    }, n));
}​

$.proxy работает по другому — он устанавливает контекст для выполняемой функции
Этот вариант не работает pastebin.com/bWWMS3Ys
Возвращает 2 вместо 1. Мне нужно чтобы t передавалось именно та, которая была на момент вызова post
Еще в книге по jQuery от 2009 было описано все это и даже больше (исключая последние нововведения, конечно). Пруф.: www.books.ru/books/jquery-podrobnoe-rukovodstvo-po-prodvinutomu-javascript-619339/

Неужели никто книги не читает?

Лучше новичкам напишите о Deffered или вызове callbacks в нужном контексте контексте через $.Proxy.
про deFeRRed уже есть статьи:
habrahabr.ru/post/113073/
habrahabr.ru/post/112960/

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

есть способ, когда можно не получать id и тогда вытаскавать его нет необходимости для примера мы хотим удалить пост при формировании html сразу вшиваем ссылку которая приведет к удалению

<a href="/comment/delete/123" class="delete">Удалить</a>

и потом уже при навешивании эвента нам не придется ничего получать можно использовать аттрибут href

$("a.delete").on("click", function() {
 $.post($(this).attr("href"), {}, function() {});
 return false;
})


если еще написать правильно серверный скрипт удаления, то можно также позволить удалить комент тем, у кого не включен js
соглсаен, иногда можно и так.
только лучше
1. не /comment/delete/123, а /comment/123/delete. Например, если у вас RESTful
2. не $('a.delete').on('click', handler), а $('.container').on('click', 'a.delete', handler); — решаем проблемы добавления событий к новым комментариям
3. в click обработчике лучше писать event.preventDefault(), чем return false. Поскольку return false это event.preventDefault() + event.stopPropagation(). Например, если у вас дополнительно собирается карта кликов — клики по ссылкам удаления не будут засчитываться
1. про рефстфул не было и речи, просто рандомная ссылка в одном из старых проектов

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

$("a.delete").live("click", function() {
 el = $(this)
 $.post(el.attr("href"), {}, function(r) {
   if (r.status == 1) {
     el.parent.hide()
   }
   else {
     $(".error", el.parent).html(r.error).show();
   }
 });
 return false;
})


но при этом уже возникает привязка к структуре html
el = $(this); // тут не хватает кстати var
и вы пытаетесь работать с r как с json, при этом явно не указывая dataType='json'. В случае если ваш сервер выдаст, например (500 ошибку) — у вас возникнет ошибка в скрипте на строке if (r.status == 1) {
точнее не 500 ошибку, а страницу с ошибкой, но код ответа будет 200
по памяти писал, так как даже; пропустил, уже года два, два с половиной не работаю с jquery ) насчет ответа сервера работал как с json, все настройки заданы в $.ajax() потому, и для jquery все было как json, все что вызывало ошибку возвращало или 200 в json или отличный код от нормального в общем общий подход понятен, я его озвучил и думаю это неплохое решение и в ряде случаев облегчает использование, так как позволяет легко тестировать еще до того, как интерфесами занялись верстальшик и js девелопер
3. в click обработчике лучше писать event.preventDefault(), чем return false. Поскольку return false это event.preventDefault() + event.stopPropagation(). Например, если у вас дополнительно собирается карта кликов — клики по ссылкам удаления не будут засчитываться

Это уже давно не так, было в ранних версиях jQuery, но они исправили.
Sign up to leave a comment.

Articles