пятница, 22 января 2010 г.

Необычные особенности JavaScript

В веб разработке не найдется людей, которым не приходилось бы работать с JavaScript. Сам язык является диалектом ECMAScript, основаным на спецификации ECMA-262. В результате реализации спецификации, язык JavaScript просто напичкан "интересными возможностями". Иногда некоторое поведение языка вызывает бурю негодования. Чтобы зверь не укусил тебя за задницу, нужно знать его повадки. В этой статье попробую описать необычные "повадки" JavaScript.

Операции суммирования и вычитания

В суммирование однотипных простых значений(типа строка, число) нет ничего особенного, и все они проводятся согласно логическим правилам исходя из типа. Многие из вас, наверное, знают про маленькую особенность, которою можно наблюдать при суммировании строки и числа. Такие моменты обусловлены правилом неявного преобразования типов. Но знаете ли вы обо всех?
var p1 = "3" + 1; // p1 = "31" (строка)
var p2 = "3" - 1;    // p2 = 2 (число)
var p3 = "3" - -"1"; // p3 = 4 (число)
Как оказывается, в результате сложения строки и числа, вы получаете строку, а вот если вы будете вычитать из строки число или из строки строку, то получите опять- таки число.

Сравнения

Сравнение имеет тоже свою магию. И, порой, можно получить просто неожиданный результат.
var n = ''=='0'; //false
var n1 = 0==''; //true
var n2 = 0=='0'; //true
var n3 = false=='false'; //false
var n4 = false=='0'; //true
var n5 = false==undefined; //false
var n6 = false==null; //false
var n7 = null==undefined; //true
var n8 = " \t\r\n"==0; //true
Еще один из интересных моментов связан со сравнением массивов.
var n = 2==[2]; // результат true
Еще более удивительным может показаться следующие сравнение
var n1 = 2==[[[2]]]; // результат true
Ну и что бы окончательно убедится, что сравнение массивов обладает истинной магией, посмотрите на вот этот пример.
var a = { "item" : 1 };
var n2 = a[[[["item"]]]]==a["item"]; // результат true

Особенность работы с типом undefined

Этот тип состоит из единственного значения undefined. Данное значение принимают все переменные, которые объявлены, но которым еще не присвоено значение.
var i = {};
var n = i.j===undefined; // результат true, значение свойства b не установлено
Особенность заключается в том, что если данной переменной undefined присвоить другое значение, то результат при сравнении не заданного свойства с этим значением будет давать значение false;
undefined = 1;
var n1 = i.j===undefined; // результат false
Для избежания ошибок в коде лучше использовать сравнение типов.
var n2 = typeof i.j=="undefined"; // результат всегда true

Преобразования строки в число

Функция parseInt преобразует строку в число по указанному основанию.
var n1 = parseInt('06'); // результат 6
var n2 = parseInt('07'); // результат 7
var n3 = parseInt('08'); // результат 0
var n4 = parseInt('09'); // результат 0
var n5 = parseInt('10'); // результат 10
Будьте бдительны при использовании этого метода :).

Преобразование в логический тип

Что бы преобразовать значение в логический тип, вам необходимо сделать следующим образом:
var n = Boolean(value);
Но есть и другой способ, для этого вам необходимо воспользоваться двойным логическим отрицанием.
var n1 = !!0; // результат false
var n2 = !!1; // результат true
var n3 = !!4; // результат true
var n4 = !!""; // резульатат false
var n5 = !!"0"; //результат true
var n6 = !!"12"; // результат true
Операции преобразования будут проведена согласно правилам преобразование к логическому типу.

Округление чисел

Для округления в JavaScript вы можете воспользоваться функциями Math.floor(x) или parseInt(x,10). Двойное побитовое NOT (~~) можно так же использовать для округления.
var n = Math.PI; // результат 3.141592653589793
var n1 = Math.floor(n); // результат 3
var n2 = parseInt(n, 10); // результат 3
var n3 = ~~n; // результат 3
Очень необычный способ, но результат возвращает корректно :).

Тип Date

Дата в JavaScript измеряется в миллисекундах, начиная от полуночи 01 января 1970 года GMT+0. Для получения даты вам нужно создать объект типа Date и передать туда необходимые параметры даты.
var currentDate = new Date(); //Текущая дата
var date = new Date(2008,07,06); // 06.07.2008
Есть интересный момент при работе с датой, связан с тем, что вы можете указывать смещение по годам, месяцам, дням, минутам, секундам. Например, вам необходимо от даты 10.10.2010 узнать дату 1024 дня.
var futureDate = new Date(2010,10,10+1024); // 30.08.2013
alert(futureDate);

Особенность работы try, catch, finally

Как мы все прекрасно знаем, для обработки исключений в javascript нам необходимо использовать конструкцию try...[catch]...[finally]. Казалось, какие особенности может иметь такая конструкция. Рассмотрев в примере от Neil Fraser, мы можем убедится, что все же тут имеется некоторые особенности. Как вы думаете, что какое значение вернет функция f()?
function f() {
  try {
      return true;
  } 
  finally {
    return false;
  }
}

j = f(); // j == false;
Как оказывается данный метод вернет значение "false".

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

Javascript имеет два способа используя которые можно получить значение свойства. Первый, обращение через ".", удобней для написания, второй, обращение как к элементу массива, будет полезен в программного доступе к значениям.
a['title'] = "JavaScript array";
a.title = "JavaScript свойства объекта";
Именно из-за этой особенности можно ответить на вопрос "Как узнать все свойства объекта?".
var obj = { param1 : JavaScript string", param2 : "Javascript date" };
var result = '';
for (var i in obj) {
  // обращение к свойствам объекта по индексу
  result += i + " = " + obj[i] + "\n";
}
alert(result);

Аргументы функции

При вызове функции вы можете не передавать значение параметров. Но вот если вы передали параметры, а в функции не определены входящие параметры, то вы можете воспользоваться переменной arguments для получения доступа ко всей коллекции полученным параметрам.
function wow(param1){
  var params = arguments; // ["hello", "world"];
}
wow("JavaScript tips", "Используем arguments JavaScript");
Что-то упустил?

6 комментариев:

  1. Браво!)
    Пишите ещё и заходите к нам ;) http://vl.vg/
    n5 = false==undefined; //false
    n6 = false==null; //false
    Сравнение булева значения с "ничем" можно было не приводить, но оно и полезно для новичков :)

    ОтветитьУдалить
  2. Спасибо, очень нужны такие статьи. Кстати с наступающим Новым Годом, дизайн какой-то праздничный:D

    ОтветитьУдалить
  3. var n2 = parseInt('07'); // результат 7

    var n3 = parseInt('08'); // результат 0

    :)

    ОтветитьУдалить
    Ответы
    1. Здесь вся магия во втором параметре принимаемым функцией parseInt(string[, radix]); Radix - основание системы счисления. Если первым значением функция принимает значение с первым нулем и radix - не указанно, то автоматически radix выставляется в значение - 8. Для получения желаемого результата при округлении десятичных чисел выставляйте вручную radix = 10.
      Т.е
      var n3 = parseInt('08', 10); // результат 8
      Никакой магии

      Удалить
    2. Магией и есть то, что при разных входящих значениях, если передается один параметр, отрабатывает разная логика. Именно такая ерунда увеличивает шанс "глупых" ошибок :).

      Удалить