четверг, 16 мая 2013 г.

Головоломный JavaScript


Головоломный JavaScript

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

Чтобы было интереснее я буду прятать ответ и решение под спойлер.

1. Так что помните, дети, всегда подставляем системы счисления!

Для начала простой, но прикольной пример. Что вернут такие вызовы parseInt?

parseInt('fuck');
parseInt('fuck', 16);
Узнать ответ
parseInt('fuck');     // NaN
parseInt('fuck', 16); // 15

Как работает parseInt: он посимвольно проверяет переданную строку на соответствие указанной вторым аргументом системе счисления и если находит некорректный символ, то завершает работу. По умолчанию, система счисления считается десятичной, при условии, что переданная строка не начинается с 0. В десятичной системе счисления символ ‘f’ недопустим и функция заканчивается свою работу не найдя ни одной цифры. А вот в шестнадцатиричной системе символ ‘f’ допустим и соответствует десятичному числу 15. Символ ‘u’ не допустим и функция завершает свою работу.


2. Может кто подскажет?

Чему равно такое выражение?

"Why am I a " + typeof + "";
Узнать ответ

“Who am I a number”

Оператор “+” обладает большим приоритетом чем “typeof”, поэтому указанная запись эквивалентна следующей:

“Why am I a ” + (typeof (+ “”)).

Унарный “+”” выполняет привидение к числу, поэтому “typeof” от результата его выполнения - это number.


3. Кто больше?

Ну и кто больше?

[1, 2, 4]         <  [1, 2, 5]
[1, 2, 'd']       <  [1, 2, 5]
[1, 2, ['d', 5]]  <  [1, 2, [20, 5]]
[1, 2, 5]         == [1, 2, 5]
[1, 2, 5]         <= [1, 2, 5]
[1, 2, 5]         >= [1, 2, 5]
Узнать ответ
[1, 2, 4]         <  [1, 2, 5]        //true
[1, 2, 'd']       <  [1, 2, 5]        //false
[1, 2, ['d', 5]]  <  [1, 2, [20, 5]]  //false
[1, 2, 5]         == [1, 2, 5]        //true
[1, 2, 5]         <= [1, 2, 5]        //true
[1, 2, 5]         >= [1, 2, 5]        //true

Согласно спецификации ECMAScript 5 для выполнения операции сравнения аргументы, которые не являются примитивами, должны быть привидены к примитивам (если кому интересно, то пункт 11.8.5 “Алгоритм сравнения абстрактного отношения”). Сначала JavaScript пробует преобразовать аргумент к числу с помощью метода valueOf и только когда это не удается приводит к строковому типу (изначально я хотел написать здесь про естественность сравнения чисел, и что когда мы говорим, что слово А больше слова Б, то имеем в виду длину. Но из беседы с коллегой выяснилось, что это не правда. Когда мы сравнимаем два слова мы инстанцируем связанные с ними образы и сравнимаем их. И только если образов не нашлось, то сравниваем слова не как метки образов, а именно как набор букв). Для массивов метод valueOf не определен и поэтому они сравниваются как строки:

"1,2,4" < "1,2,5" //true
"1,2,d" < "1,2,5" //false

Но все вышесказаное верно только для операций сравнения. В случае оператора “==”” привидение к примтивам осуществляется только если один из аргументов примитив, а во всех остальных случаях оператор “==” возвращает true только если оба аргумента ссылаются на один объект (пункт 11.9.3 “Алгоритм сравнения абстрактного равенства”), что в нашем случае не так.

Следует заметить, что для объектов сравнение работать не будет, т.к. их дефолтный toString возвращает [object Object].

Ладно, объекты сравнивать нельзя, но почему бы не проверять массивы на равенство с помощью сравнения? Все пишут циклы, а ведь можно обойтись одной строкой:

!(arr1 < arr2)&&!(arr1 > arr2)

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

var arr1 = [],
    arr2 = [],
    res,
    start,
    end,
    len = 600000;

for(var i=0; i<len; i++){
    arr1[i] = i;
    arr2[i] = i;
   // if(i == len-100) arr2[i] = i+1; //чтобы делать не равные массивы
}

//проверим, что массивы создались
console.log(arr1.length, arr2.length);

//наш метода
start = new Date();

res = !(arr1 < arr2)&&!(arr1 > arr2);

end = new Date();

console.log(end.getTime() - start.getTime(), res);

//классический циклический
start = new Date();

for(var i=0; i<len; i++)
    res &= (arr1[i] === arr2[i]);

end = new Date();

console.log(end.getTime() - start.getTime());

Разница поражает: 123мс на 2015мс в пользу привидения типов!

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


понедельник, 22 апреля 2013 г.

IE10 и input

 Из серии "Заметки на полях", вдруг кому пригодится.

Верстка не моя сильная сторона, но на меня свалилась бага в IE10, решения которой в рунете не нашлось. Спешу поделится очередными хаками для очередного IE.

Компания из Редмонда опять пошла своим путем и вместо улучшения рендеринга добавила новые прибамбасы в input. Теперь они сами дорисовывают input-ам кнопки очистки поля (Clearing Text):


и кнопку показа пароля (Verifying Password):



К счастью MSDN сам же рассказывает как это выключить:

sel::-ms-clear {
    display: none;
}

и

sel::-ms-reveal {
    display: none;
}

где sel - это селектор нужного элемента, т.е. по хорошему это просто input.

P.S.: в добавок ко всему данная "фича" воспроизводится не во всех IE10 и прямой зависимости от точной версии и номера билда не обнаружено.

понедельник, 15 апреля 2013 г.

GNOME Shell Extensions

GNOME Shell введенный вместе с GNOME3 крайне спорная штука. Если первые два поколения гнома копировали оконные интерфейс Windows, то третий в корне сменил интерфейс, но сделал это намного удачнее чем метрокафель. Да, он стал намного прожорлевее из-за красивостей и того, что написан на JavaScript, но зато он стал гибкой платформой для пользовательских виджетов. За счет того, что это JavaScript, писать их легко и приятно + легко интегрировать с другими с веб-страницами. За счет этого факта было реализовано хранилище расширений, которое позволяет устанавливать новые дополнения одним кликом в браузере: extensions.gnome.org.

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

пятница, 12 апреля 2013 г.

openSUSE, Node.js и libv8

Из серии "Заметки на полях", вдруг кому пригодится.

После дежурного обновления системы неожиданно развалился мой сервер на node.js. При запуске пишет следующую ошибку:

node: symbol lookup error: node: undefined symbol: _ZN2v86LockerC1EPNS_7IsolateE

Текущие версии пакетов в репах:

libv8: 3.17.16.0-140.1
nodejs: 0.8.18-21.1

Путем перебора установлено, что корректно работает следующее сочетание версий:

libv8: 3.12.19.1-1.9.1
nodejs: 0.6.19-1.1.2

Теперь, во избежание новых капризов, обновления заблокировал.

P.S.: чтобы пост был не таким скучным, результат вставки лога ошибки в поиск Яндекса:


вторник, 9 апреля 2013 г.

Влад III Валашский

Мумифицировавшийся трупик старого сайта переехал с народа на укоз. Не особо приятно, но в целом пофиг и не это главное. При просмотре не сломалось ли чего обнаружил несколько заметок, которые не относятся к школьному юмору, а претендуют на небольшое историческое исследование. Прошу строго стиль не судить, писалось это лет 7 назад, а править стилистику сейчас не хочется. Итак, первая из двух заметок "из детства", которые хочу вам представить:

Влад III Валашский

Все знают Дракулу, многие знают Влада Цепеша, но мало тех, кто знает Влада III Валашского...
  
Все знают, или хотя бы уже догадались, что это один и тот же человек. Бесспорно правда то, что это всё имена одного и того же человека, но правильнее было бы выразится, что это три ипостаси одного и того же человека. Для полноты портрета попытаемся понять каждую сущность в отдельности. 


пятница, 22 марта 2013 г.

Облегчаем себе жизнь в консоли

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

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



среда, 13 марта 2013 г.

Красота спасет мир

reStructuredText

Уважаемый @rcassum в свойственной питонистам манере делать геморрой на ровном месте все автоматизировать решил не пользоваться красивым UI и создавать свой написальщик файлов. Поскольку на работе я успешно использую для написания Reference Guide язык разметки reStructuredText, то тоже решил немного поиграться с автоматизацией.

Утилита для превращения RST в HTML нашлась легко: в бездонных репозитория openSUSE существует пакет python-docutils, который содержит утилиты для превращения RST во все основные текстовые форматы. Кроме консольной утилиты нашелся и графический редактор ReText. Но у обоих утилит обнаружился большой недостаток: по сути отсутствует подсветка синтаксиса. Специально для таких эстетов нашлась библиотека Pygments, которая предоставляется пакетом python-Pygments. Повозившись немного с питоном в попытках сотворить собственный скрипт, который связал бы все вместе, махнул рукой и взял рабочий проект на базе Sphinx.