2008-11-20

Нестандартное поведение стандартного оператора ||

Иногда при кросс браузерном программировании бывает нужно выбрать из двух или более переменных которые зависят от типа браузера. Например типичный пример - отслеживание событий мыши - в IE параметры события берутся из глобального объекта event а в Firefox и многих других браузерах event передается как формальный параметр в обработчик события. Поэтому необходимо выбирать тот или иной способ получения этого объекта в зависимости от того какой браузер.

Самое первое, что приходит на ум это использовать тернарный оператор "<condition>?<if true>:<if false>"

a.onclick = function(e){
  var ev = e?e:event;
  //далее работаем с ev
}

Сегодня мне предложили еще более короткую запись:

a.onclick = function(e){
  var ev = e||event;
  //далее как обычно
}

Все отлично, все логично, но почему это работает? В MSDN четко сказано что || оператор логический и возвращает он true или false в зависимости от входных параметров. Если параметры на входе не логические то приводятся к логическим, т.е. не должно так работать а работает.

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

    var v1; //undefined
    var v2 = {};
    var result = v1 || v2;    
    alert(result===v2); //true

Интересно, такое поведение где нибудь документировано или это хак?

UPD: Оказыватся у Мозиллы все подробно на этот счет расписано:

https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Operators/Logical_Operators

 

Коментариев: 7

 
  2008-11-11

Базовый класс для наследования в JavaScript

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

Основные особенности следующие:
- маленький и простой - неминифицированный размер: 622 байта.
- конструктор описывается явно как функция с именем 'constructor'
- наследование статических и обычных членов класса
- при определениии объекта не используется MyClass.prototype;
- не используются глобальные функции для создания цепочек прототипов;
- не изменяется Object.prototype.

 Вот пример использования:

var Animal = BaseClass.extend({
  constructor:function(){
    alert("Anumal is created!");
  },
  say:function(){
    alert("hm...");
  }

});

ver Cow = Animal.extend({
  constructor:function(){
    alert("Cow is created!");
  },
  say:function(){
    alert("mooo");
  }  

});
var cow1 = new Cow();
cow1.say();

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

Upd. Позже я пересмотрел мысль насчет super и включил её в реализацию метода. В ztools.org можно найти последнюю версию функции.

 

Коментариев: 1

 
  2008-10-23

!! в JavaScript

Разглядывая чужие исходники постоянно натыкаюсь на использование конструкций вида !!(document.evaluate). Догадывался что это проверка переменной на существование, и вот теперь убедился с этом лично.

alert(!!document.evaluate);

Если выполнить указанный код в мозилле покажет true если в Explorer - покажет false, что и требовалось доказать т.к. Explorer не поддерживатет XPath.

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

 

Оставить комментарий

 
  2008-10-21

JavaScript наследование

Разбирая исходники библиотеки mootolls обнаружил ссылку на блог некоего Дина Эдвардса (Dean Edwards). Дин предлагает свою версию эмуляции объектно-ориентированного программирования на JavaScript.

Основные особенности следующие: не нужно кажный раз для расширения класса писать MyClass.prototype; можно обращаться к методам базового класса из переопределенных методов (аналог super в Java); поддержка статических методов свойств; не используются глобальные функции для создания цепочек прототипов; не изменяется Object.prototype.

Вобщем довольно интересная штука, хотя на мой взгляд super в общем то не очень и нужен, хотя идея сама по себе, на мой взгляд, классная и реализация отличная.

 

Оставить комментарий

 
  2008-10-21

jQuery, Prototype - Исправляем родовые травмы браузеров

При создании проектов где требуется достаточно сложное программирование на JavaScript нередко начинаешь задумываться над использованием какой нибудь библиотеки для облегчения кодирования. В частности, к числу таких библиотек принадлежат jQuery и Prototype.

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

Однако, если задуматься над тем что предоставляют эти библиотеки такого без чего совершенно нельзя обойтись и раде чего мы готовы пожертвовать размером приложений - это поддержка XPath, лучшая кроссбраузерная совместимость, разный sugar типа анимации, ajax утилит и т.п.

Однако странная вещь обе эти библиотеки реализованы прямо скажем довольно своеобразно - jQuery - для обеспечения кроссбраузерности оборачивает все объекты с которыми работает в собственный объект jQuery через алиаc $. в результате код выглядит примерно вот так:

$(document).ready(function(){ $('.deletelink').click(function(){ if (confirm('Are you sure to delete this blog?')){ return true; } return false; }); });

Prototype напротив использует вызовы типа $('id_of_element') для вызова элемента по его ID при этом "расширяя" объект дополнительными методами.

Нужно ли говорить что оба подхода не способствуют эффективности. Зачем так сделано? Почему все так странно? Оказывается ответ прост! Internet Explorer и Safary не поддерживает переопределение методов HTMLElement.prototype! Все элементарно - из-за нестандартного повседения одного браузера разработчики вынуждены прыгать через голову, выворачиваться наизнанку, изобретать велосипед.

 

Оставить комментарий

 
  2008-06-30

Таскание мышью используя JavaScript

Здесь работающий пример как сделать сабж. Потаскайте мышью красный квадрат. Работает в IE и FF, в других браузерах тоже должно, хотя и не тестировал.
 

Оставить комментарий

 
  2008-06-20

Как проставить неразрывный пробел (&nbsp;) с использованием document.createTextNode

Долгое время не получалось при работе со структурой документа использовать спец символы типа &nbsp; - если пишешь что-то типа document.createTextNode('&nbps') то получается не неразрывный пробел а его html представление поэтому приходилось присваивать свойство innerHTML вместо того чтобы оставаться в рамках модели XML DOM что не очень то красиво.

Просто createTextNode не понимает html разметки, ему нужно скармливать символы как они есть без использования html замен, но вот беда, на клавиатуре у нас нет неразрывного пробела - есть только обычный. Оказывается набрать неразрывный пробел можно на клавиатуре - подсказка в виндовой таблице символов - нажимаем alt и не отпуская набираем на дополнительной клавиатуре 0160 (в режиме Num Lock), отпускаем alt - появляется пробел - но это не обычный пробел а самый что не на есть неразрывный, html код которого и есть &nbsp; его можно вставлять в createTextNode без проблем.

 

Оставить комментарий

 
  2008-06-19

Private методы и свойства в JavaScript

Наткнулся на замечательную статью про то как в JavaScript можно создавать приватные методы и свойства для объектов. Никогда не задумывался над этим под таким углом, но вещь несомненно очень интересная.
 

Оставить комментарий

 
  2008-06-05

onReady

Сегодня клиенты пожаловались что если что нибудь на странице не загрузилось то не работатет часть JavaScript'овского функционала - конкретно у них не сработала загрузка видео с ютуба - чето последнее время у них не быстро там все работает. Просто основная логика на странице подключается с использованием события onLoad - в принципе штука не обязательная в человечьих браузерах, но вот в Эксплорере при попытки поменять что либо до этого события возникает очень плохая ошибка.

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

Оказывается вносить изменения в объектную модель браузера можно и до возникновения события onLoad, т.е. когда не все изображения еще подгружены

ниже привожу функцию для отслеживания момента когда в браузере становится возможным вносить изменения в объектную модель документа. Идея позаимствована из JQuery

/** * faster way to load content in browser idea taken frin JQuery * this allows do not wait until data will be completely loaded * seems only opera can allow load faster using this function - * though in JQuery they say it's supported... */ //alert(document.addEventListener); function bindReady(){ if ( bindReady.readyBound ) return; bindReady.readyBound = true; if (document.addEventListener){ document.addEventListener( "DOMContentLoaded", bindReady.ready, false ); } // Mozilla, Opera (see further below for it) and webkit nightlies currently support this event // If IE is used and is not in a frame // Continually check to see if the document is ready if ( Object.isIE && window == top ) (function(){ if (bindReady.isReady) return; try { // If IE is used, use the trick by Diego Perini // http://javascript.nwbox.com/IEContentLoaded/ document.documentElement.doScroll("left"); } catch( error ) { setTimeout( arguments.callee, 0 ); return; } // and execute any waiting functions bindReady.ready(); })(); if ( Object.isSafari || Object.isOpera ) { var numStyles; (function(){ if (bindReady.isReady) return; if ( document.readyState != "loaded" && document.readyState != "complete" ) { setTimeout( arguments.callee, 0 ); return; } bindReady.ready(); })(); } } bindReady.readyBound = false; bindReady.isReady = false; bindReady.ready = function(){ bindReady.isReady = true; var i; for (i=0;i

Тестировал в IE6/IE7, Safari, Opera, FF. Не нравится только как работает в Опере - там скрипт срабатывает позже onLoad, в остальных браузерах гораздо раньше

 

Оставить комментарий

 
  2008-04-29

Касперский зажигает

Сегодня попросили меня показать как на JS сделать опрос удаленного сервера по HTTP, ну код для этого совершенно тривиальный:

var fso = new ActiveXObject('Scripting.FileSystemObject'); var f = fso.CreateTextFile('C:\\test.txt'); var http = new ActiveXObject('XMLDOM3.XMLHTTP'); http.open('http://www.microsoft.com'); http.send(); var f.Write(http.ResponseText);

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

 

Коментариев: 1