10 несуразностей и секретов JavaScript
JavaScript. Причудливый и все-таки прекрасный язык программирования. Если бы Пабло Пикассо был программистом, то он наверняка бы разработал именно JavaScript. Null является объектом, пустой массив эквивалентен false
, а функции перебрасываются словно теннисные мячи.
Типы данных и определения
1. null
- это объект
Начнем с широко известной странности JavaScript. null
является объектом. Сомневаетесь? Ведь данное утверждение противоречит самой сути null
. Вот доказательства:
alert(typeof null); //Выдаст сообщение 'object'
Несмотря на очевидный факт, null
не является реализацией никакого базового объекта. (Если вы не знали, значения в JavaScript являются реализациями базового объекта. Так, каждое число является реализацией объекта Number
, каждый объект является реализацией объекта Object
.) Такое положение возвращает нас обратно к практическому смыслу, потому что если null
является отсутствием значения, то он не может быть реализацией какого-либо объекта. Следовательно следующее выражение возвращает false
:
alert(null instanceof Object); //Выдаст сообщение 'false'
2. NaN
- это число
Считаете факт представления null
объектом странным? Попробуйте проверить NaN
! Он оказывается числом! Кроме того, NaN
не равен самому себе!
alert(typeof NaN); //Выдаст сообщение 'Number' alert(NaN === NaN); //Выдаст сообщение 'false'
В действительности NaN
не равен ничему. Единственный способ проверить значение NaN
- функция isNaN()
.
3. Массив без ключей == false
Другая причуда JavaScript:
alert(new Array() == false); //Выдаст сообщение 'true'
Чтобы понять, что происходит,, нужно понимать концепцию истина и ложь. В данном случае имеется некий вид отношений истина/ложь, которая может привести в восторг философа или специалиста по логике.
Существует множество описаний концепции истины и лжи, но самое простое объяснение таково: в JavaScript каждое нелогическое значение имеет встроенный логический флаг, который используется тогда, когда значение должно рассматриваться как логическое, например, при сравнении с другим логическим выражением.
Чтобы произвести сравнение значений разных типов JavaScript сначала приводит их к общему типу данных. False
, 0, null
, undefined
, пустая строка и NaN
становятся false
—?только для заданного выражения сравнения. Например:
var someVar = 0; alert(someVar == false); //Выдаст сообщение 'true'
Здесь имеется попытка сравнить число 0
с логическим значением false
. Так как типы данных несопоставимы, JavaScript незаметно приводит их к единому логическому эквиваленту, и в нашем случае 0
представляется как false.
В выше приведенном списке не было пустого массива. Пустой массив - любопытная штука: в действительности он рассматривается как true
, но при сравнении с логическим значением он ведет себя как false
. Вот так!
var someVar = []; //Пустой массив alert(someVar == false); //Выдаст сообщение 'true' if (someVar) alert('hello'); //Выполняется alert, поэтому someVar рассматривается как true
Чтобы избежать приведения типов нужно использовать оператор сравнения значений и типов ===
(в отличие от ==
, который сравнивает только значения). Например:
var someVar = 0; alert(someVar == false); //Выдаст сообщение 'true' alert(someVar === false); //Выдаст сообщение 'false', 0 - число, а не логическая переменная
Регулярные выражения
4. replace() может получать возвратную функцию
Это один из самых скрытых секретов JavaScript (который появился начиная с версии 1.3). Обычно вызов функции replace()
выглядит примерно так:
alert('10 13 21 48 52'.replace(/d+/g, '*')); //заменяем все числа на *
Простая замена. Но что если нужно более сложно контролировать когда и как будет производиться замена? Например, нужно заменять числа только до 30. Такая задача не может быть решена только регулярным выражением (оно может сделать все, что угодно со строкой, но не с математикой выражения). Нужно использовать возвратную функцию для вычисления соответствия.
alert('10 13 21 48 52'.replace(/d+/g, function(match) { return parseInt(match) < 30 ? '*' : match; }));
Для каждой проверки JavaScript вызывает функцию, передавая ей аргументы для проверки. А затем мы возвращаем либо звездочку, либо само число.
5. Регулярные выражения: больше, чем выделение подстроки и замена
Обычно JavaScript программисты в своей практике используют только методы match
и replace
для регулярных выражений. Но кроме них в JavaScript есть и другие инструменты.
Практический интерес представляет метод test()
, который действует подобно match
, но не возвращает значение: он просто подтверждает соответствие шаблону. То есть он легче для вычислений.
alert(/w{3,}/.test('Hello')); //Выдаст сообщение 'true'
Выше приведенный код выполняет проверку на соответствие шаблону, состоящему из трех и более буквенных и числовых символов. Так как строка Hello
соответствует требованию, то мы получаем true
. Но мы не получаем выделение из строки, а просто результат проверки.
Также обратите внимание на то, что с помощью объекта RegExp
вы можете создавать динамические регулярные выражения. В основном регулярные выражения составляются с использованием коротких форм (то есть строк, заключенных в прямые слеши) и в них нельзя использовать переменные. Но RegExp()
позволяет обойти ограничение.
function findWord(word, string) { var instancesOfWord = string.match(new RegExp('\b'+word+'\b', 'ig')); alert(instancesOfWord); } findWord('car', 'Carl went to buy a car but had forgotten his credit card.');
Здесь мы создаем динамический шаблон на основе значения аргумента word
. Функция возвращает количество совпадений полного слова word
(то есть не являющегося частью других слов) в строке. В нашем примере car
встречается один раз, а слова Carl
и card
игнорируются.
Так как RegExp
определяется строкой, а не через синтаксис с обратными слешами, то мы можем использовать переменные для построения шаблона. Но специальные символы в данном случае требуют к себе повышенного внимания, как символы границы слова в нашем примере.
Функции и область видимости
6. Вы можете обманывать область видимости
Область видимости, в которой выполняется код, определяет доступность переменных. Свободный код JavaScript (то есть код, который выполняется вне какой-либо функции) оперирует глобальной областью видимости объекта window
, где имеет доступ ко всему. А локальные переменные, объявленные внутри функции, доступны только внутри данной функции, но не вне ее.
var animal = 'dog'; function getAnimal(adjective) { alert(adjective+' '+this.animal); } getAnimal('lovely'); //Выдаст сообщение 'lovely dog';
В данном примере наша переменная и функция объявлены в глобальной области видимости (то есть в window
). Так как this
всегда указывает на текущую область видимости, то здесь он указывает на window
. Следовательно функция ищет window.animal
. Нормальная ситуация. Но мы можем заставить нашу функцию считать, что она выполняется в другой области видимости, которая отличается от ее нормального состояния. Для этого используется встроенный метод call()
для вызова функции:
var animal = 'dog'; function getAnimal(adjective) { alert(adjective+' '+this.animal); }; var myObj = {animal: 'camel'}; getAnimal.call(myObj, 'lovely'); //Выдаст сообщение 'lovely camel'
Здесь функция выполняется не в window,
а в myObj
, что определяется первым аргументом при вызове метода call.
По существу метод call()
имитирует ситуацию, что наша функция является методом myObj
. Обратите внимание, что все переданные аргументы после первого в метод call()
передаются в нашу функцию - здесь lovely
становится значением аргумента adjective
.
Опытные разработчики JavaScript наверняка скажут, что годы работают без использования данного метода, потому что хорошо продуманный код не нуждается в шаманстве с бубнами. Но, тем не менее, описанная ситуация представляет определенный интерес.
Также есть метод apply(),
который действует аналогично call()
, за исключением того, что аргументы должны быть указаны в массиве. Выше приведенный пример с использованием apply()
будет выглядеть так:
getAnimal.apply(myObj, ['lovely']); //аргументы функции отправляются как массив
7. Функция может вызывать сама себя
Сложно отрицать следующий факт:
(function() { alert('hello'); })(); //Выдаст сообщение 'hello'
Синтаксис примера достаточно прост: мы объявляем функцию и немедленно вызываем ее, как другую с помощью синтаксиса ()
. Может возникнуть вопрос "А зачем так делать?". Обычно, функция содержит код, который планируется использовать позже и в другом месте, иначе не нужно размещать его в функции.
Хорошим примером использования самовызывающихся функций (они иногда обозначаются аббревиатурой SEF) является привязка текущего значения переменной для использования внутри отложенного кода, такого как возвратные функции для событий, таймаутов и интервалов. Есть проблема:
var someVar = 'hello'; setTimeout(function() { alert(someVar); }, 1000); var someVar = 'goodbye';
Новички бывают удивлены тем, что Newbies функция alert
в timeout
выдает goodbye,
а не hello
. Ответ достаточно прост возвратная функция timeout
не вычисляет значения someVar
до момента своего выполнения, поэтому в ней оказывается значение goodbye
.
Самовызываюшиеся функции обеспечивают решение данной проблемы. Вместо определения возвратной функции имплицитно, как в выше приведенном примере, мы возвращаем ее из самовызывающейся функции, в которую передаем текущее значение someVar
в качестве аргумента. то есть мы передаем и изолируем текущее значение переменной someVar
, защищая его от последующих модификаций someVar
. Очень похоже на фотографию, которая хранит образ во времени.
var someVar = 'hello'; setTimeout((function(someVar) { return function() { alert(someVar); } })(someVar), 1000); var someVar = 'goodbye';
В данном примере код выдаст сообщение hello
, так как используется изолированное значение someVar
(то есть аргумент функции, а не внешняя переменная).
Браузеры
8. Firefox читает и возвращает значение цвета в формате RGB, а не hex
Непонятно, почему Mozilla так делает. Определенно, из JavaScript удобнее работать с форматом hex, а не RGB. Например:
<!-- #somePara { color: #f90; } --> Текст <script> var ie = navigator.appVersion.indexOf('MSIE') != -1; var p = document.getElementById('somePara'); alert(ie ? p.currentStyle.color : getComputedStyle(p, null).color); </script>
Большинство браузеров выведут ff9900
, а Firefox - rgb(255, 153, 0)
. Нужно использовать функцию JavaScript для конвертации RGB в hex.
Обратите внимание, что в данном случае мы говорим о вычисляемом цвете, а не о том, как он определяется для элемента. Также IE имеет отличный метод для вычисления стилей.
Метод jQuery css()
возвращает значение, определяемое в стиле для элемента. Поэтому, для действительного значения нужно использовать getComputedStyle
и currentStyle
.
Разное
9. 0.1 + 0.2 !== 0.3
Данная причуда касается не только JavaScript, а всего компьютерного окружения и проявляется во многих языках. Вычисленное значение равно 0.30000000000000004.
Это действие точности вычислений. Когда JavaScript производит вычисления, он конвертирует значения в бинарные эквиваленты. И здесь появляется проблема, так как 0.1 не может быть совершенно точно представлено в бинарном эквиваленте, который используется для бинарных операций с плавающей точкой.
Для того чтобы преодолеть данный казус есть два метода (выбор за вами):
- Конвертирование значений в целые, вычисления, а затем обратная конвертация к десятичным дробям.
- построение логики так, чтобы работать с диапазоном чисел, а не точным значением.
Например, вместо такого кода:
var num1 = 0.1, num2 = 0.2, shouldEqual = 0.3; alert(num1 + num2 == shouldEqual); //Выдаст сообщение 'false'
Можно построить выражение так:
alert(num1 + num2 > shouldEqual - 0.001 && num1 + num2 < shouldEqual + 0.001); //Выдаст сообщение 'true'
В данном примере результат сложения 0.1 + 0.2 оценивается как попадание в диапазон чисел около 0.3 с точностью 0.001. Для точных вычислений такой метод явно подходит плохо.
10. Undefined может быть Defined
Звучит, конечно, странно, но undefined
не является зарезервированным словом в JavaScript, хотя и имеет специальное значение для выявления неопределенных переменных:
var someVar; alert(someVar == undefined); //Выдаст сообщение 'true'
На первый взгляд все отлично. Но:
undefined = "Я имею значение!"; var someVar; alert(someVar == undefined); //Выдаст сообщение 'false'!
Источник: http://feedproxy.google.com/~r/ruseller/CdHX/~3/gymyb1VuAtI/lessons.php
Дайджест новых статей по интернет-маркетингу на ваш email
Новые статьи и публикации
- 2024-11-26 » Капитан грузового судна, или Как начать использовать Docker в своих проектах
- 2024-11-26 » Обеспечение безопасности ваших веб-приложений с помощью PHP OOP и PDO
- 2024-11-22 » Ошибки в Яндекс Вебмастере: как найти и исправить
- 2024-11-22 » Ошибки в Яндекс Вебмастере: как найти и исправить
- 2024-11-15 » Перенос сайта на WordPress с одного домена на другой
- 2024-11-08 » OSPanel 6: быстрый старт
- 2024-11-08 » Как установить PhpMyAdmin в Open Server Panel
- 2024-09-30 » Как быстро запустить Laravel на Windows
- 2024-09-25 » Next.js
- 2024-09-05 » OpenAI рассказал, как запретить ChatGPT использовать содержимое сайта для обучения
- 2024-08-28 » Чек-лист: как увеличить конверсию интернет-магазина на примере спортпита
- 2024-08-01 » WebSocket
- 2024-07-26 » Интеграция с Яндекс Еда
- 2024-07-26 » Интеграция с Эквайринг
- 2024-07-26 » Интеграция с СДЕК
- 2024-07-26 » Интеграция с Битрикс-24
- 2024-07-26 » Интеграция с Travelline
- 2024-07-26 » Интеграция с Iiko
- 2024-07-26 » Интеграция с Delivery Club
- 2024-07-26 » Интеграция с CRM
- 2024-07-26 » Интеграция с 1C-Бухгалтерия
- 2024-07-24 » Что такое сторителлинг: техники и примеры
- 2024-07-17 » Ошибка 404: что это такое и как ее использовать для бизнеса
- 2024-07-03 » Размещайте прайс-листы на FarPost.ru и продавайте товары быстро и выгодно
- 2024-07-01 » Профилирование кода в PHP
- 2024-06-28 » Изучаем ABC/XYZ-анализ: что это такое и какие решения с помощью него принимают
- 2024-06-17 » Зачем вам знать потребности клиента
- 2024-06-11 » Что нового в работе Яндекс Метрики: полный обзор обновления
- 2024-06-11 » Поведенческие факторы ранжирования в Яндексе
- 2024-06-11 » Скорость загрузки сайта: почему это важно и как влияет на ранжирование
Все мы сидим в сточной канаве, но некоторые при этом смотрят на звезды Уайльд Оскар - (1854-1900) - английский писатель |
Мы создаем сайты, которые работают! Профессионально обслуживаем и продвигаем их , а также по всей России и ближнему зарубежью с 2006 года!
Как мы работаем
Заявка
Позвоните или оставьте заявку на сайте.
Консультация
Обсуждаем что именно Вам нужно и помогаем определить как это лучше сделать!
Договор
Заключаем договор на оказание услуг, в котором прописаны условия и обязанности обеих сторон.
Выполнение работ
Непосредственно оказание требующихся услуг и работ по вашему заданию.
Поддержка
Сдача выполненых работ, последующие корректировки и поддержка при необходимости.