5 полезных приемов

    Эти маленькие куски кода я насобирал за весь свой стаж JavaScript-программирования. Они должны серьезно облегчить жизнь Web-разработчика, и научить решать проблемы проще, не прикручивая тяжеловесные JavaScript-библиотеки. Не спорю, иногда они могут оказаться весьма полезными, но подгружать JQuery для создания таймера — это, по-моему, дикость…



    Прием №1:

    В Интернете очень мало документации по удалению объектов средствами JavaScript. На одном из форумов мне так вообще сказали, что это невозможно. На самом деле — не только возможно, но и очень просто:

    function Kill(object) {
    object.innerText = null;
    object.innerHTML = null;
    object.outerHTML = null;
    object = null;
    }


    Объект, передаваемый в первом и единственном аргументе функции, удаляется полностью. DOM это элемент, или переменная, все равно от объекта ничего не останется. Если, например, из функции убрать первые две строки, к объекту нельзя больше будет обратиться, но HTML элемент никуда не денется. К функции можно дописать что-то вроде этого:

    if(typeof(object)=="string"){object=document.getElementById(object)};

    Для автоматизации процесса. Тогда вместо самой ссылки на объект, можно передать в качестве аргумента id какого-нибудь HTML элемента.

    Прием № 2:

    Из предисловия взят. Таймеры. Ну, мне кажется, достаточное количество народу знают про функции setInterval() и clearInterval(). Но некоторые программисты заблуждаются, думая, что заставить циклически выполняться можно только независимый JavaScript код, написанный в кавычках:

    i = setInterval("alert('Hello, World!')",3000)

    Все не так плохо! В реальности, вместо строки туда можно засунуть объект-функцию, несмотря на то, что передавать функции в аргументы и не принято:

    i = setInterval(abc(),3000)

    Некоторые пытаются передать функцию в кавычках, как строку, и ничего у них не выходит. Поскольку JavaScript гибок, как русские гимнастки, можно вообще написать все так:

    i = serInterval(function{код_здесь},3000)

    Так что таймер сделать действительно несложно.

    Прием № 3:

    AJAX многие любят. И в JavaScript иногда полезно реализовать функцию через обращение к скрипту на сервере. То есть:

    bin2hex(number)

    Вычислится на стороне сервера, а мы просто получим ответ. Одна проблема: на выполнение задания и передачу данных нужно время. Кто же нашу функцию ждать-то будет? Да никто! Можно использовать синхронные HTTP-запросы, которые «повесят» всю Web-страницу, пока не придет ответ. Здорово и легко:

    function getXmlHttp(){
    var xmlhttp;
    try {
    xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) {
    try {
    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    } catch (E) {
    xmlhttp = false;
    }
    }
    if (!xmlhttp && typeof XMLHttpRequest!='undefined') {
    xmlhttp = new XMLHttpRequest();
    }
    return xmlhttp;
    }

    function Get(url) {
    var xmlhttp = getXmlHttp()
    xmlhttp.open('GET',url, false);
    xmlhttp.send(null);
    if(xmlhttp.status == 200) {
    //код здесь
    }
    }

    Вот только у пользователя инфаркт случится, когда его страница перестанет реагировать на события клавиатуры и мыши. Плюс, добавит масла в огонь какой-нибудь Chrome ("ОПАНЬКИ! Страница не отвечает!"). Так что гораздо лучше использовать асинхронные запросы, которые вызовет другую функцию, как только ответ будет получен:

    function Get(url,whattado) {
    var xmlhttp = getXmlHttp()
    xmlhttp.open('GET',url, true);
    xmlhttp.onreadystatechange = function() {
    if (xmlhttp.readyState == 4) {
    if(xmlhttp.status == 200) {
    whattado(xmlhttp.responseText);
    }
    }
    };
    xmlhttp.send(null);
    }



    Опять же, никто не запрещает писать:

    Get('file.txt',function(txt){alert(txt)})

    И браузер не зависнет, и программист порадуется.

    Прием № 4:

    Обходите Runtime Errors! Рядовой пользователь не знает про существование консоли и будет обижен, если какая-то кнопка на странице перестанет выполнять свои действия, вообще никак не реагируя (а, ведь, именно так случится, если произойдет ошибка). Используйте конструкцию try..catch для ловли исключений:

    try
    {
    document.write(junkVariable)
    }

    catch(e)
    {
    alert(e.message)
    }

    Можно, кстати, вызывать исключения самостоятельно, оператором throw(). Но тогда вместо объекта message следует обращаться к его родительскому объекту напрямую:

    try
    {
    //код_здесь
    throw «Error5»
    }
    }

    catch(e)
    {
    if(e == «Error5»){alert(«Ошибка № 5»)}
    }

    Прием №5:

    Однажды, мне понадобилось создавать Read-only переменную для хранения версии JavaScript библиотеки. Понятно, что проблема с этим не только у меня, но странно, почему все требуют «Read-only variables», а не «Constants in JavaScript». Так вот, констант в JavaScript нет. Есть в ECMAScript, но тогда наша страница перестает быть кроссбраузерной, а заказчик в ту же секунду перестает нас кормить. Read-only переменные создаются с помощью Getter:

    var lib = {
    get version() {return 5}
    }

    lib.version == 5, т.е. ведет себя как переменная, а не функция.

    Кроссбраузерная версия приема выглядит так:

    var lib = {
    this.__defineGetter__(«version»,function(){return 5});
    }

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

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

      +7
      1) Удаление элементов не всегда так просто. Например, для тэгов IMG для браузеров на основе WebKit надо чистить поле src, иначе изображение так и останется в памяти. Но при этом надо проверять, что мы не под Android, ибо там такая операция вызывает крах браузера.

      2) в jQuery API нет ничего для таймеров.

      5) Тут надо бы красным выделить код — пока не поддерживается в большинстве браузеров.

      Ну и, конечно, синтаксическая подсветка не помешала бы. тэг source, атрибут lang.
        –2
        В идеале надо вообще все свойства обнулить, перед обнулением объекта.

        Кроссбраузерная версия 5-го примера осуществляется через __defineGetter__ и __defineSetter__
          –1
          Как же так, в jQuery нет, а пост на Хабрахабре — есть? http://habrahabr.ru/blogs/jquery/42809/ Колдовство!
            0
            Это плагин!
              –3
              А я разве сказал, что они не относятся к делу?
      • НЛО прилетело и опубликовало эту надпись здесь
          +4
          прием номер 1 загадочен и не верен.
          Чтобы гарантированно уничтонить дом ноду достаточно сделать простые действия.
          1. добавить ее в некий элемент
          2. сказать этому самому родительскому элементу innerHTML=''
          3. профит и полное изничтожение.
          (это кстати рекомендованное поведение для IE)
            +11
            Такое ощущение, что автор никогда не пытался прочитать ни одной книги по JavaScript. Методом тыка открыл для себя несколько не очевидных в начале решений, которые знают все, и решил поделится ими со всем миром.

            Во-первых, в любой литературе по JavaScript, указывается как работают эти функции в разных браузерах и с каких версий поддерживаются. Реализаций JavaScript с ходу с десяток наберется.
            Еще понравились введения в AJAX & try-catch.

            Автор, я не могу поверить, что вы прочитали хотя-бы две книжки по JavaScript и там не было try-catch. Стоит ли писать статьи, если вы сами их никогда не читаете?
              +4
              i = setInterval(abc(),3000)

              А так разве будет работать корректно? Нужно ведь только передать имя функции, а не вызывать её тут же.
                +6
                хотел это написать
                но может у него
                function abc() {
                return function() {
                alert('abc');
                }
                }
                +1
                Зачем велосипед в п.3?
                jQuery ajax/get/post никто не отменял еще
                  +1
                  Затем что некоторые разработчики считают что нужно понимать как все работает. И да jQuery далеко не стандарт JS разработки, я видел очень мало хорошего кода на jQuery, в основном поделки школьников.
                    +1
                    Ну во-первых одно другому не мешает. Я для себя кучу интересных моментов открыл читая код jQuery.
                    А во-вторых jQuery уже по-большому счету стандарт. Пруф
                    В третьих, если у меня разработчик будет писать хрень подобную выше — огребет по полной, потому что бесцельно тратит рабочее время на выдумывание велосипеда.
                      +1
                      Я бы сказал что эти графики говорят только о росте деградации :)
                        –1
                        Деградации? Можно посмотреть ваши проекты?
                          +3
                          Попробую объяснить свою позицию. jQuery популярен, и набирает обороты по понятной причине, низкий порог вхождения, им действительно просто пользоваться, для простых вещей, как раз по этим причинам качество кода и страдает.

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

                          Тем не менее я совсем не против jQuery, я не говорил что это плохой инструмент, а только о том какие плагины он пораждает. Я бы даже хотел использовать jQuery каждый день чтобы получить много хорошего опыты, так как заказчики любят эту библиотеку :)
                            +1
                            Кстати вот как раз по теме свежий перевод Фреймворки делают разработчиков тупыми?
                              +1
                              В статью особо не вчитывался, поскольку она о Джаве, от которой я далёк и не знаю роли фреймворков в ней.
                              Но, по-моему, (для client-side и jQuery, в частности) проблема не столько во фреймворках, сколько в людях, пишущих на них. Фреймворки сильно снижают порог вхождения, скрывая сложность многих действий от пользователя. Взять, например, те же CSS селекторы в jQuery: если бы пользователь реализовывал выборку нужного элемента вручную (DOM traversing), он бы знал, чего это стоит браузеру и кешировал узлы в переменных вместо повторной выборки каждый раз.

                              Но суровая реальность такова, что зачастую люди начинают знакомство с языком с библиотеки / фреймворка, что влечёт, например, такой синдром как jQuery головного мозга. В особо запущенных случаях больные считают jQuery и JS совершенно разными языками и зачастую спрашивают, как портировать какой-либо функционал (скажем, сопоставление адреса страницы с регэкспом) с JS на jQuery.
                              Начинать знакомство с языком с фреймворка, я считаю, строго противопоказано.
                          0
                          Это мое личное мнение, основанное на просмотре исходников многих jQuery плагинов, готов принять все минусы, потому как истина дороже :)
                          0
                          И да, про код jQuery речи не было, если кто-то смотрит исходники используемых инструментов, то уже понятно что он разработчик, я лишь указываю на тенденцию.
                        0
                        Ради как-то примитивной интерактивности подключать jQuery тоже не совсем правильно.
                          –1
                          У меня jQuery подключается во всех проектах на этапе создания, а не когда необходимость возникнет, потому что понадобится 100%.
                            0
                            подключи еще ExtJS… вдруг Ext.direct'ом данные подгружать захочешь )
                        0
                        5. См. также defineProperty в ECMAScript 5

                        var obj = {};
                         
                        Object.defineProperty( obj, "value", {
                           value: true,
                           writable: false,
                           enumerable: true,
                           configurable: true
                         });
                        


                        И относительно кроссбраузерности: kangax.github.com/es5-compat-table/ — все относительно.
                          +11
                          ад
                            +4
                            Приём N1: ну заменили вы локальную переменную на null и что?
                              +3
                              var object = {aaa:"aaa", bbb:"bbb"};
                              
                              function Kill(object) {
                              object.innerText = null;
                              object.innerHTML = null;
                              object.outerHTML = null;
                              object = null;
                              }
                              
                              Kill(object);
                              alert(object);
                              


                              Выдает object :(
                                0
                                а что мешает вызвать delete object;
                                  0
                                  Ничто. Только зачем?
                                    0
                                    а что мешает вызвать delete object;

                                    Для локальных переменных сработает некорректно.
                                    0
                                    По всей видимости, имелось ввиду, что последнее присваивание надо делать в месте вызова, а не в функции.
                                    Впрочем, не совсем понятно, кто и когда запретил delete.
                                      0
                                      delete по отношению к переменным запретила спецификация. Можно только к свойствам объекта.
                                        0
                                        Вот он — понедельник во всей красе.
                                    0
                                    Спасибо, кэп, что бы мы без тебя делали
                                      0
                                      Кэп поддельный. Советы не очевидны, а вредны.
                                        0
                                        Разумеется, это вообще какой-то джедайский путь
                                      +22
                                      Видимо вы не тестировали ваш код в браузерах. А еще видимо не понимаете как работает DOM, как «работают» объекты в браузере, как уничтожаются, что есть сборщик мусора и как он работает.
                                      Вот вам код для экспериментов:
                                      function Kill(object) {
                                      object.innerText = null;
                                      object.innerHTML = null;
                                      object.outerHTML = null;
                                      object = null;
                                      }
                                      var a = document.createElement('div');
                                      a.className = 'asd';
                                      var b = document.createElement('div');
                                      b.appendChild(a);
                                      alert(b.innerHTML);  // <div class="asd"></div>
                                      Kill(a);
                                      b.appendChild(a);  // (1) важная строка, я буду на нее ссылаться
                                      alert(b.innerHTML);  // <div class="asd"></div>  
                                      alert(a.outerHTML);  // (2) <div class="asd"></div>  
                                      

                                      Вы кажется обещали полное уничтожение после вызова Kill? Так вот, как видите div, сохраненный в переменной a, жив здоров.
                                      Учим мат часть:
                                      1. Свойства innerHTML, innerText и outerHTML — это интерфейсные свойства для html элемента, это по сути getter'ы/setter'ы. Когда вы их меняете это приводит к определенным действиям со стороны браузера, он переводит все это в некие DOM операции.
                                      2. innerText — нестандартное свойство, оно всегда было в IE, потом стало поддерживаться некоторыми другими браузерами, но его нет в стандарте. По сути операция чтения реализуется через выборку всех текстовых узлов и конкатенацию их значений (nodeValue), а запись — через экранирование данных и запись в innerHTML, либо же операциями DOM:
                                      object.innerHTML = '';
                                      object.appendChild(document.createTextNode(text));
                                      

                                      Поэтому нет смысла обнулять innerHTML и innerText — достаточно обнулить innerHTML.
                                      3. Свойства outerHTML тоже нет в стандарте. IE и webkit его поддерживают, но запись в свойство равносильно следующему:
                                      function setOuterHTML(element, html){
                                        if (element.parentNode) // если нет родителя, операция бессмысленна
                                        {
                                          var fragment = document.createDocumentFragment();
                                          var tmp = document.createElement('div');
                                          tmp.innerHTML = html;
                                          while (tmp.lastChild)
                                            fragment.appendChild(tmp.lastChild);
                                          element.parentNode.replaceChild(fragment, element);
                                        }
                                      }
                                      

                                      То есть если элемент находится в другом элементе, то он замещается на новый html. При этом разрушения, как вы предполагали, не происходит — об этом говорит строка (1) — outerHTML не изменился, но да, элемент был изъят из своего родителя. По этой причине если убрать строку (2), то в родителе b элемента a не будет.
                                      Но для изъятия узла из его родителя есть более простой способ:
                                        if (node.parentNode)
                                          node.parentNode.removeChild(node);
                                      

                                      4. Свойств innerText и outerHTML нет в стандарте, так как они не атомарны, неоднозначны и относительно легко эмулируются. Firefox не поддерживает эти свойства, поэтому он не удалит элемент из другого как вы предполагаете, поэтому даже без строки (1) все останется на своих местах.
                                      5. Задание значений свойствам DOM узла браузерно-зависимо. Подразумевается что innerHTML/outerHTML/innerText содержат текстовые значения, поэтому значения будет приводится к строке.
                                      object.innerHTML = value;
                                      // IE поймет это так
                                      object.innerHTML = String(value);
                                      // webkit
                                      object.innerHTML = value == null ? '' : String(value);
                                      

                                      Соответственно вместо пустого значения, в IE вы получите строку 'null'. При задании outerHTML = null, в IE вместо кода удаляемого узла будет 'null', в webkit пустая строка.
                                      6. Особо «порадовало»:
                                      function (object){
                                        ...
                                        object = null;
                                      }
                                      

                                      DOM это элемент, или переменная, все равно от объекта ничего не останется. Если, например, из функции убрать первые две строки, к объекту нельзя больше будет обратиться, но HTML элемент никуда не денется.

                                      В js в функцию объекты передаются по ссылке. То есть object это всего лишь переменная, которая содержит ссылку на целевой объект. От ее обнуления ничего не изменится. Да, после того как вы обнулили переменную, внутри функции обратиться к объекту нельзя — но объект по прежнему существует и к нему можно обращаться, как можно увидеть из кода, который я привел.
                                      Нет смысла внутри функции присваивать null для оbject, так как это и так произойдет на выходе из функции.
                                      7. Чтобы уничтожить объект, нужно убрать все ссылки на него, тогда сборщик мусора сам разрушит объект. Если вы уверены что на узел не ссылаются переменные, достаточно сделать:
                                        if (node.parentNode)
                                          node.parentNode.removeChild(node);
                                      
                                        0
                                        респект, разобрано по косточкам. плюс пример нюансов из первого моего комментария, для полноты, и RIP.
                                          0
                                          Вот ради таких комментариев и нужны такие посты.
                                          +3
                                          i = setInterval(abc(),3000)


                                          Функции setInterval и setTimeout принимают качестве первого значения функцию (имя функции), либо строку.
                                          В случае строки, ее значение конвертируется javascript.
                                          В вашем примере abc видимо возвращает строку, либо функцию — так как она вызывается сразу, а не через 3 секунды. Хотя больше похоже на опечатку, и скобок здесь быть не должно.
                                            0
                                            Автор, советую почитать книги (не блоги, не стать, не переводы) раз появилось желание разрабатывать на JS, начать с азбуки (синтаксис, возможности), потом всякие плюшки и приемы (развивает мыслительный процесс) — Stefanov, Zakas, Resig и тд.
                                              +1
                                              Автор уже вторую статью слабал, того же уровня :)
                                                0
                                                Начать стоит с полезных статей на хабре, в которых уже собрали множество полезных советов и ответы на множество вопросов, где в том числе есть и ссылки на сопутствующие статьи:
                                                JavaScript F.A.Q: Часть 1
                                                JavaScript F.A.Q: Часть 2
                                                  0
                                                  Не соглашусь, по моему начать следует с азбуки, по крайней мере автору. Приведенный FAQ полезен не отрицаю, но это все есть в приведенных книгах второго уровня.
                                                    0
                                                    Аффтару надо читать:

                                                    Название DOM Scripting: Web Design with JavaScript and the Document Object Model
                                                    Apress Series
                                                    Авторы Jeremy Keith, Jeffrey Sambells
                                                    Соавтор Jeffrey Sambells
                                                    Издание: 2
                                                    Издатель Apress, 2010
                                                    ISBN 1430233893, 9781430233893
                                                    Количество страниц Всего страниц: 336

                                                    там не про фреймворки
                                                    ;-)
                                                  0
                                                  Alexei White?!

                                                  Название JavaScript Programmer's Reference
                                                  Автор Alexei White
                                                  Издатель John Wiley and Sons, 2010
                                                  ISBN 0470577843, 9780470577844

                                                  Только он почему-то оброс волосами и помолодел за год, судя по обложке, если сравнить её с изданием 2009 г.
                                                  0
                                                  > i = serInterval(function{код_здесь},3000)
                                                  serInterval — сэр Интервал?

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

                                                  Самое читаемое