2008-12-19

Корректный способ итерации сквозь объекты

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

Допустим, у нас есть объект созданный вот таким образом:

var obj = {property1:"свойство 1",property2:"свойство 2"};

вот самый распространенный НЕПРАВИЛЬНЫЙ способ показать все свойства объекта:

for(key in obj){
        alert(key);
}

Вроде все работает правильно и на экране действительно последовательно покажутся все свойства объекта. Почему такой способ является неправильным?

Добавим перед циклом вот такую строчку:

Object.prototype['test1'] = "test1 value";

При запуске скрипта еще раз оказывается, что наш объект волшебным образом приобретает еще одно свойство - test1, хотя мы его не создавали! Это значит что любая сторонняя библиотека которая таким способом расширяет функциональность стандартных классов JavaScript, например prototype.js способна непредсказуем образом изменить логику работы ваших программ. В данном случае хорошим тоном является сравнение текущего свойства и свойства прототипа при каждой итерации, если они равны, значит ничего не делаем:

for(key in obj){
   if (obj.constructor.prototype[key]!==obj[key]){
      alert(obj[key]);
   }
}

Обратите внимание, что здесь использовано строгое сравнение !==. Все просто, все логично, вот только набирать это каждый раз довольно утомительно, поэтому создадим вот такую функцию:

    function forEach(obj,fn){
        for(key in obj){
            if (obj.constructor.prototype[key]!==obj[key]){
                if (fn(key)===false) break;
            }
        }
    }

В этом случае итерация запишется совсем просто:

forEach(obj,function(key){
    alert(obj['key']);
});

Обратите внимание, что в функции forEach есть возможность остановить итерацию досрочно, что бывает полезно например при поиске элемента, для этого достаточно возвратить false:

forEach(obj,function(key){
    alert(obj['key']);
    if (key=='property1') return false;
});

 

 

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

 
  2008-12-11

Native in Chrome

Обнаружил что в Google Chrome в JavaScript нельзя создать переменную с именем native - оказывается это ключевое слово зарезервированное на будущее. Интресно что Safari который работает на том же самом движке все работает.

 

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

 
  2008-12-04

Эмбриопрограммирование

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

shortEvents:function(names){
     x.forEach(names,function(key){
       this[names[key]] = new Function("fn","remove","this.on('"+[names[key]]+"',fn,remove)");
     },this)
},

Кто догадается что это?

 

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

 
  2008-11-28

Почему мне не нравится CodeIgniter

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

GET data is simply disallowed by CodeIgniter since the system utilizes URI segments rather than traditional URL query strings (unless you have the query string option enabled in your config file). The global GET array is unset by the Input class during system initialization.

Т.е. пользуйтесь господа разработчики тем что дают и не пользуйтесь тем что есть. т.е. подход такой что CodeIgniter это не система в которой ПОТЕНЦИАЛЬНО можно сделать секюрно, это система в которой ПОТЕНЦИАЛЬНО нельзя сделать несекюрно.

Конечно подход хорош, но мне он не понравился, наверно я до него еще не дорос, или наоборот перерос...

Пришлось передавать данные не через GET а через параметор в адресе, но параметры через адресную строку передаются только буквенно-цифровые - а мне нужно было передать URL для редиректа, поначалу решил закодировать параметр как base64, но как оказалось что base64 оставляет кой какие не-буквенно-цифровые символы, например знаки == на конце текста, иногда. Тогда решил просто заменить все символы их числовыми представлениями в шестнадцатеричной системе - это прокатило.

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

/**
 * Этим кодируем
 */
function an_encode($str){
 $result = '';
 for($i=0;$i<strlen($str);$i++){
  $result .= dechex(ord($str[$i]));
 }
 return $result;
}
/**
 * Этим декодируем
 */
function an_decode($str){
 $result = '';
 for($i=0;$i<strlen($str)/2;$i++){
  $result .= chr(hexdec($str[$i*2].$str[$i*2+1]));
 }
 return $result;
}

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

 

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

 
  2008-11-25

Получение POST данных в PHP скрипте

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

Вот практическая задача - как из программы на PHP получить данные посланные методом POST. Казалось бы нет ничего проще - бери переменную $_POST и смотри что в ней. Но... Переменная $_POST полезна только в том случае если данные были посланы в виде пар имя+значение, т.е. например через HTML форму. Однако, в ряде практических задач приходится иметь дело не с HTML формами, например, если имеем дело с XML преданным непосредственно методом POST - тут стандартная переменная $_POST не подходит.

В PHP для того чтобы непосредственно получить POST данные есть переменная - $HTTP_RAW_POST_DATA - но, она определена только если в php.ini включена always_populate_raw_post_data а она по умолчанию выключена - конечно ее можно включить через .htaccess но только если php стоит как модуль Апача, а это как правило сделано не всегда.

Все мы знаем, что в CGI приложения POST данные передаются через стандартный поток ввода. Значит, если открыть стандартный поток ввода по его имени в PHP он называется input то можно прочитать его содержимое:

$r = file_get_contents("php://input"); //contents of POST buffer

Указанный метод, похоже, работает всегда - и для модуля Апача и для CGI и к настройкам php.ini он не чувствителен.

 

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

 
  2008-11-25

Создание анимированного GIF при помощи GD

Задался вопросом - можно ли используя стандартные средства PHP создать анимированный GIF? Оказывается можно и довольно просто. Для этого уже создан замечательный класс - GIFEncoder, который можно скачать с phpclasses.org - правда сайт требует регистрации.

Используя этот класс сделал быстренько простенький генератор ajax прелоадеров - вот таких:

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

Исходник здесь

 

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

 
  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-11-10

Опрос вебсервера по протоколу HTTP

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

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

 

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

 
  2008-10-30

strpos vs. ereg vs. preg_match

Тут возник вопрос как между собой соотносится быстродействие POSIX регулярных выражений, Perl-совместимых регулярных выражений и кодирования "в лоб" с использованием обчных си-подобных str* функций. Можно долго на эту тему рассуждать, поэтому привожу тест который расставляет все по местам. Исходник здесь

 

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