10 особенностей и тайн javascript

Очень вольный перевод статьи от SmashingMagazine  Ten Oddities And Secrets About JavaScript

Переменные и типы данных

1. Null как объект. Ключевое слово null в JavaScript имеет специальный смысл. У значения null объектный тип и оно говорит об отсутствии объекта. Значение null уникально и отличается от любых других. Если переменная равна null, следовательно, в ней не содержится допустимого объекта, массива, числа, строки или логического значения.1
Когда значение null используется в логическом контексте, оно преобразуется в значение false, в числовом контексте оно преобразуется в значение 0, а в строковом контексте— в строку "null"

2. NaN это число. Расшифровывается как Not A Number. Обычно это значение возвращается при ошибке выполнения операций с числами. Тем не менее NaN одновременно и является числом и при этом не равно само себе. Как вам эта идея?

В самом деле NaN не равно ни к чему. Единственный способ проверить что переменная содержит NaN,  через функцию isNaN()

3. Массив без ключей == false (Правда и ложь).
Вот еще одна особенность.

Чтобы понять почему это так, вы должны понимать концепцию правды и лжи. И она отличается от той, которую вы могли получить, изучая логику или философию. Самое простое объяснение, в Javascript каждое не булево значение имеет свой логический флаг(true|false), который присваивается только на время сравнения с логическим значением.

False, zero, null, undefined, пустые строки и NaN эквивалентны false не постоянно, а только для данного выражения. Пример:

В данном примере мы пытаемся сравнить 0 и false. Поскольку типы отличаются, Javascript приводит первое значение к логическому и мы получаем false==false.

Пустые массивы ведут себя более странно. Пустой массив в выражении вычисляется как true, однако в сравнении с логическим значением эквивалентен false. Запутал? Иллюстрирую.

Чтобы избежать приведения типов, нужно использовать оператор сравнения типов === (== сравнивает только значения).

Обсудить подробнее концепцию правды и лжи, можно в блоге автора . Ну а если есть желание понять, что происходит изнутри, когда Javascript сравнивает два значения, добро пожаловать в section 11.9.3 of the ECMA-262 документации.

Регулярные выражения

4. replace() может принимать функцию обратного вызова. Эта малоизвестная особенность появилась Javascript 1.3. Обычно replace() используют так.

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

После каждого совпадения с регулярным выражением, Javascript передаст совпадение(match) как аргумент callback функции. В примере если значение меньше 30, то произойдет замена на "*", если нет то заменит себя в том же месте.

5. Регулярные выражения: больше чем match и replace. Большинство разработчиков Javascript знают и используют только match() и replace() . Но есть и другие методы.

Особый интерес представляет test() , который работает как match, но он не возвращает совпадения, лишь подтверждает совпадение с шаблоном.

В примере, строка Hello содержит более 3 букв или цифр , поэтому совпадает с шаблоном.

Также интересен Regexp, объект который позволяет создавать динамические регулярные выражения. Большинство регулярных выражений пишется в сокращенной форме (заключены в косую черту, как мы это показывали выше). Таким образом нельзся сссылаться на переменые и невозможно создавать динамических выражений. С Regexp() вы избавлены от этого недостатка.

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

Функции и видимость

6. Делаем переменную видимой глобально. (You Can Fake Scope — как бы правильней перевести?) Область видимости означает где переменные и функции доступны, и в каком контексте они исполняются.
Выражения javascript(те которые не в теле функции) исполняются в контексте обьекта window. Они будут доступны для всего, что исполняется в window.

this всегда указывает на текущую область видимости, в данном случае window (если исполняется в броузере). Таким образом функция ищет и находит window.animal . Но мы можем дать знать нашей функции, что она исполняется в другой видимости используя call() метод.

В примере функция уже работает в видимости объекта myObj.

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

Метод apply(), аналогичен call(), но аргументы функции задаются в виде массива.

7. функции могут исполнять сами себя.

Мы объявляем функцию и сразу же ее запускаем используя синтаксис () . Кажущееся противоречие: функция содержит код, который мы хотим запустить позже, не сейчас, иначе мы бы не помещали код в функцию.

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

Новички в форумах неизменно спрашивают, почему alert в timeout выдает goodbye и не hello ?  Ответ прост,  callback функция внутри timeout() исполняется уже тогда, когда someVar перезаписана goodbye.

SEFs позволяет решить эту проблему.

В данном примере мы изолировали someVar внутри функции, используя как аргумент и в результате alert выдаст hello.

Браузер

8. Firefox читает и возвращает цвета в RGB, а не Hex . Я никогда не понимал, почему Mozilla делает это.

Хотя большинство браузеров будет возвращать ff9900 , Firefox возвращает rgb(255, 153, 0) . Обратите внимание, что когда я говорю, вычисляется цвет, я имею в виду текущий цвет, независимо от того, как он применяется к элементу.

Разное

9. Особенности вычислений с плавающей точкой 0.1 + 0.2 !== 0.3 . Это встречается во многих языках программирования и не только в Джаваскрипт. Результ этого выражения 0,30000000000000004.

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

Как обойти эту проблему? Решения выходят за рамки данной статьи, но в общем виде сводятся к двум вариантам:
1. Преобразовать чилса в целые, совершить вычисление и потом, преобразовать в десятичное число результат.
2. Поменять логику сравнения, чтобы она учитывала диапазон.

10. Undefined Can Be Defined. Как ни странно это может звучать, undefined в действительности не является зарезервированным словом в JavaScript, хотя оно имеет особое значение и является единственным способом узнать определена ли переменная.

Это нормальное поведение. Но:

Вы так же можете посмотреть Список Mozilla зарезервированных слов в JavaScript

You may also like...

  • 4 пункт удивил, удобно.
    А вот про 9…Если работа с массивом дробных чисел, то для вычисления всё в целое сначала переводить? Бредово.
    Тут всё зависит от того, какая нужна точность. Погрешность в 10+ знаке не критично для большинства операций. А если нужна точность, юзайте внешние средства. Под WIN можно к MatLab через COM, к примеру.

  • Никита

    var someVar = ‘hello’;
    setTimeout((function() { alert(someVar); })(someVar), 1000);
    var someVar = ‘goodbye’;
    Функция выполняется сразу, а не через заданный промежуток времени.

  • ZenCoder.pro

    Спасибо. Кое что интересное почерпнул из области вычислений с плавающей точкой.