чему равно 0 2 undefined true false

2d37f7837f00054aae22f11379cfcbec

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

Содержание

Проверь себя

Вот список интересных выражений, о которых мы только что говорили:

Тут полно такого, что выглядит более чем странно, но без проблем работает в JS, задействуя неявное приведение типов. В подавляющем большинстве случаев неявного приведения типов в JS лучше всего избегать. Рассматривайте этот список как упражнение для проверки ваших знаний о том, как работает приведение типов в JavaScript. Если же тут для вас ничего нового не нашлось — загляните на wtfjs.com.

image loader
JavaScript полон странностей

Неявное преобразование типов и явное преобразование типов

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

Три вида преобразования типов

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

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

▍Преобразование к типу String

Все примитивные типы преобразуются в строки вполне естественным и ожидаемым образом:

В случае с типом Symbol дело несколько усложняется, так как значения этого типа можно преобразовать к строковому типу только явно. Здесь можно почитать подробности о правилах преобразования типа Symbol.

▍Преобразование к типу Boolean

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

▍Преобразование к типу Number

Неявное приведение значения к числовому типу — тема более сложная, так как оно применяется, пожалуй, чаще чем преобразование в строку или в логическое значение. А именно, преобразование к типу Number выполняют следующие операторы:

Вот как в числа преобразуются примитивные значения:

Вот два особых правила, которые стоит запомнить:

При применении оператора == к null или undefined преобразования в число не производится. Значение null равно только null или undefined и не равно ничему больше.

Значение NaN не равно ничему, включая себя. В следующем примере, если значение не равно самому себе, значит мы имеем дело с NaN

Преобразование типов для объектов

Вот псевдо-реализация метода [[ToPrimitive]] :

В целом, работа алгоритма выглядит следующим образом:

Вот пример поведения Date при преобразовании типов:

Стандартные методы toString() и valueOf() можно переопределить для того, чтобы вмешаться в логику преобразования объекта в примитивные значения.

Метод Symbol.toPrimitive ES6

Разбор примеров

Вооружённые теорией, вернёмся к выражениям, приведённым в начале материала. Вот каковы результаты вычисления этих выражений:

Разберём каждый из этих примеров.

▍true + false

Оператор + с двумя операндами вызывает преобразование к числу для true и false :

▍12 / ‘6’

▍«number» + 15 + 3

▍15 + 3 + «number»

▍[1] > null

Оператор сравнения > выполняет числовое сравнение [1] и null :

▍«foo» + + «bar»

▍’true’ == true и false == ‘false’

▍[] + null + 1

Логические операторы || и && в процессе работы приводят значение операндов к логическому типу, но возвращают исходные операнды (которые имеют тип, отличный от логического). Значение 0 ложно, а значение ‘0’ истинно, так как является непустой строкой. Пустой объект <> так же преобразуется к истинному значению.

▍[1,2,3] == [1,2,3]

Этот пример лучше объяснить пошагово в соответствии с порядком выполнения операций.

▍new Date(0) — 0

▍new Date(0) + 0

Итоги

Преобразование типов — это один из базовых механизмом JavaScript, знание которого является основой продуктивной работы. Надеемся, сегодняшний материал помог тем, кто не очень хорошо разбирался в неявном преобразовании типов, расставить всё по своим местам, а тем, кто уверенно, с первого раза, никуда не подсматривая, смог решить «вступительную задачу», позволил вспомнить какой-нибудь интересный случай из их практики.

Уважаемые читатели! А в вашей практике случалось так, чтобы путаница с неявным преобразованием типов в JavaScript приводила к таинственным ошибкам?

Источник

JavaScript: загадочное дело выражения null >= 0

affdf93c733b489e879c311b9c521ce0

Однажды я собирал материалы чтобы устроить ликбез по JavaScript для пары коллег. Тогда я и наткнулся на довольно интересный пример, в котором рассматривалось сравнение значения null с нулём. Собственно говоря, вот этот пример:

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

Хотя поначалу я оставил это без особого внимания, решив, что всё дело в том, что JavaScript — это JavaScript, со всеми его странностями, этот пример меня заинтриговал. Связано ли это с типом null и с тем, как он обрабатывается, или с тем, как выполняются операции сравнения значений?

В итоге я решил докопаться до сути происходящего и начал рыться в единственном источнике истины для JavaScript — в спецификации ECMA. Сегодня я хочу рассказать вам о том, в какую глубокую кроличью нору я в результате провалился.

Абстрактный алгоритм сравнения для отношений

Рассмотрим первое сравнение:

Шаги 1 и 2 предлагают нам вызвать оператор ToPrimitive() для значений null и 0 для того, чтобы привести эти значения к их элементарному типу (к такому, например, как Number или String ). Вот как ToPrimitive преобразует различные значения:

Входной тип Результат
Undefined Преобразование не производится
Null Преобразование не производится
Boolean Преобразование не производится
Number Преобразование не производится
String Преобразование не производится
Object Возвращает значение по умолчанию для объекта. Значение по умолчанию для объекта получается путём вызова для объекта внутреннего метода [[DefaultValue]] с передачей ему опциональной подсказки ПредпочтительныйТип.
Входной тип Результат
Undefined NaN
Null +0
Boolean Результат равен 1, если аргумент равен true. Результат равен +0, если аргумент равен false.
Number Преобразование не производится

Итак, почему null не больше и не меньше нуля мы выяснили. Теперь идём дальше — разберёмся с тем, почему null ещё и не равен нулю.

Абстрактный алгоритм сравнения для равенств

Рассмотрим теперь проверку на равенство null и 0 :

Теперь, когда ещё одна «тайна» JavaScript» раскрыта, разберёмся с оператором «больше или равно».

Оператор больше или равно (>=)

Выясним теперь, почему истинно такое выражение:

Тут спецификация полностью выбила меня из колеи. Вот как, на очень высоком уровне, работает оператор >=:

В результате мы и получаем:

Итоги

Уважаемые читатели! Знаете ли вы о каких-нибудь странностях JavaScript, которые, после чтения документации, уже перестают казаться таковыми?

Источник

undefined

undefined возвращается, если переменная была объявлена, но значение переменной не было установлено.
Например:

В логе мы видим undefined :

undefined также может возникнуть, если свойство объекта не существует.

или функция имеет отсутствующий параметр:

Проверить тип можно с помощью ключевого слова typeof :

undefined может быть задан явно:

Схожие черты

Давайте посмотрим на их сходства.

Вышеприведенное выведет Нет.

также выведет Нет.

Оба являются примитивными значениями

Примитивные типы данных обрабатываются по значению.

Различия

Вы ожидали, что тип null вернет «null«? Правда? Это ошибка в JS существует уже на протяжении почти двух десятилетий, но дело в том, что она не может быть исправлена. Потому, что тысячи сайтов зависят от такого неправильного поведения, исправление которого приведет к их поломке.

Тесты для null

Как мы уже видели, undefined преобразовывается в » undefined «, а null преобразовывается в » object «.

Мы можем легко проверить на undefined:

Для null, мы не можем этого сделать:

typeof null возвращает » object «, и у нас может возникнуть соблазн переписать все вышеперечисленное следующим образом:

Но многие сложные типы данных возвращают объекты, тип может быть проверен через typeof :

Давайте посмотрим, что происходит, когда строгое и не строгое равенство выполняется для обоих типов.

Сравнение равенств

Не строгое сравнение:

Строгое сравнение:

будет false. Почему? Потому, что null => object не тот же тип, что и undefined => undefined.

Передача null и undefined в качестве аргумента функции

Мы должны быть осторожны при объявлении значения аргумента по умолчанию таким образом:

Если вы пытаетесь проверить на null аргумент, помните, так лучше не делать:

или вы можете делегировать функции проверку на null:

вы можете использовать функцию isNull в любом месте вашей программы:

Заключение

Источник

Базовые операторы, математика

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

Термины: «унарный», «бинарный», «операнд»

Прежде, чем мы двинемся дальше, давайте разберёмся с терминологией.

Унарным называется оператор, который применяется к одному операнду. Например, оператор унарный минус «-» меняет знак числа на противоположный:

Бинарным называется оператор, который применяется к двум операндам. Тот же минус существует и в бинарной форме:

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

Математика

Поддерживаются следующие математические операторы:

Первые четыре оператора очевидны, а про % и ** стоит сказать несколько слов.

Взятие остатка %

Возведение в степень **

В выражении a ** b оператор возведения в степень умножает a на само себя b раз.

Математически, оператор работает и для нецелых чисел. Например, квадратный корень является возведением в степень 1/2 :

Сложение строк при помощи бинарного +

Давайте рассмотрим специальные возможности операторов JavaScript, которые выходят за рамки школьной арифметики.

Обычно при помощи плюса ‘+’ складывают числа.

Но если бинарный оператор ‘+’ применить к строкам, то он их объединяет в одну:

Обратите внимание, если хотя бы один операнд является строкой, то второй будет также преобразован в строку.

Как видите, не важно, первый или второй операнд является строкой.

Вот пример посложнее:

Например, вычитание и деление:

Приведение к числу, унарный +

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

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

Необходимость преобразовывать строки в числа возникает очень часто. Например, обычно значения полей HTML-формы — это строки. А что, если их нужно, к примеру, сложить?

Бинарный плюс сложит их как строки:

Поэтому используем унарный плюс, чтобы преобразовать к числу:

С точки зрения математика, такое изобилие плюсов выглядит странным. Но с точки зрения программиста тут нет ничего особенного: сначала выполнятся унарные плюсы, которые приведут строки к числам, а затем бинарный ‘+’ их сложит.

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

Приоритет операторов

В том случае, если в выражении есть несколько операторов – порядок их выполнения определяется приоритетом, или, другими словами, существует определённый порядок выполнения операторов.

Из школы мы знаем, что умножение в выражении 1 + 2 * 2 выполнится раньше сложения. Это как раз и есть «приоритет». Говорят, что умножение имеет более высокий приоритет, чем сложение.

В JavaScript много операторов. Каждый оператор имеет соответствующий номер приоритета. Тот, у кого это число больше, – выполнится раньше. Если приоритет одинаковый, то порядок выполнения – слева направо.

Отрывок из таблицы приоритетов (нет необходимости всё запоминать, обратите внимание, что приоритет унарных операторов выше, чем соответствующих бинарных):

Приоритет Название Обозначение
17 унарный плюс +
17 унарный минус
16 возведение в степень **
15 умножение *
15 деление /
13 сложение +
13 вычитание
3 присваивание =

Присваивание

Присваивание = возвращает значение

Тот факт, что = является оператором, а не «магической» конструкцией языка, имеет интересные последствия.

Вызов x = value записывает value в x и возвращает его.

Благодаря этому присваивание можно использовать как часть более сложного выражения:

В примере выше результатом (a = b + 1) будет значение, которое присваивается переменной a (то есть 3 ). Потом оно используется для дальнейших вычислений.

Забавное применение присваивания, не так ли? Нам нужно понимать, как это работает, потому что иногда это можно увидеть в JavaScript-библиотеках.

Однако писать самим в таком стиле не рекомендуется. Такие трюки не сделают ваш код более понятным или читабельным.

Присваивание по цепочке

Рассмотрим ещё одну интересную возможность: цепочку присваиваний.

Опять-таки, чтобы код читался легче, лучше разделять подобные конструкции на несколько строчек:

Польза от такого стиля особенно ощущается при быстром просмотре кода.

Сокращённая арифметика с присваиванием

Часто нужно применить оператор к переменной и сохранить результат в ней же.

Эту запись можно укоротить при помощи совмещённых операторов += и *= :

Источник

Выражения и операторы

Эта глава описывает выражения и операторы языка JavaScript, такие как операторы присваивания, сравнения, арифметические, битовые, логические, строчные, и различные специальные операторы.

Полный и детальный список операторов и выражений также доступен в этом руководстве.

Операторы

В JavaScript есть следующие типы операторов. Данный подраздел описывает каждый тип и содержит информацию об их приоритетах друг над другом.

В свою очередь унарная операция использует один операнд, перед или после оператора:

Операторы присваивания

Существуют также составные операторы присваивания, которые используются для сокращённого представления операций, описанных в следующей таблице:

Деструктуризация

Операторы сравнения

Замечание: (=>) не оператор, а нотация Стрелочных функций.

Арифметические операторы

Арифметические операторы (en-US) используют в качестве своих операндов числа (также литералы или переменные) и в качестве результата возвращают одно числовое значение. Стандартными арифметическими операторами являются сложение (+), вычитание (-), умножение (*), и деление (/). При работе с числами с плавающей точкой эти операторы работают аналогично их работе в большинстве других языках программирования (обратите внимание, что деление на ноль возвращает бесконечность Infinity ). Например:

Кроме того, JavaScript позволяет использовать следующие арифметические операторы, представленные в таблице:

Битовые (поразрядные) операторы

Битовые операторы (en-US) обрабатывают свои операнды как последовательности из 32 бит (нулей и единиц), а не как десятичные, шестнадцатеричные или восьмеричные числа. Например, десятичное число 9 имеет двоичное представление 1001. Битовые операторы выполняют операции над таким двоичным представлением, но результат возвращают как обычное числовое значение JavaScript.

Следующая таблица обобщает битовые операторы JavaScript.

Битовые операторы

a

Оператор Использование Описание
Побитовое И (en-US) a & b Возвращает единицу в каждой битовой позиции, для которой соответствующие биты обеих операндов являются единицами.
Побитовое ИЛИ (en-US) a | b Возвращает единицу в каждой битовой позиции, для которой один из соответствующих битов или оба бита операндов являются единицами.
Исключающее ИЛИ (en-US) a ^ b Возвращает единицу в каждой битовой позиции, для которой только один из соответствующих битов операндов является единицей.
Побитовое НЕ (en-US) Заменяет биты операнда на противоположные.
Сдвиг влево (en-US) a Сдвигает a в двоичном представлении на b бит влево, добавляя справа нули.
Сдвиг вправо с переносом знака (en-US) a >> b Сдвигает a в двоичном представлении на b бит вправо, отбрасывая сдвигаемые биты.
Сдвиг вправо с заполнением нулями (en-US) a >>> b Сдвигает a в двоичном представлении на b бит вправо, отбрасывая сдвигаемые биты и добавляя слева нули.

Битовые логические операторы

Основной смысл работы битовых логических операторов состоит в следующем:

Примеры работы битовых операторов

Обратите внимание, что все 32 бита преобразуются с использованием битового оператора НЕ, и что величины с наиболее значимым (самым левым) битом равным 1 представляют собой отрицательные числа (в представлении дополнения до двух).

Битовые операторы сдвига

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

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

Операторы сдвига перечислены в следующей таблице.

Логические операторы

Логические операторы (en-US) обычно используются с булевыми (логическими) значениями; при этом возвращаемое ими значение также является булевым. Однако операторы && и || фактически возвращают значение одного из операндов, поэтому, если эти операторы используются с небулевыми величинами, то возвращаемая ими величина также может быть не булевой. Логические операторы описаны в следующей таблице.

Примерами выражений, которые могут быть преобразованы в false являются: null, 0, NaN, пустая строка («») или undefined.

Следующий код демонстрирует примеры использования оператора && (логическое И).

Следующий код демонстрирует примеры использования оператора || (логическое ИЛИ).

Сокращённая оценка

Так как логические выражения вычисляются слева направо, они проверяются на возможность выполнения сокращённой оценки с использованием следующих правил:

Правила логики гарантируют, что данные вычисления всегда корректны. Обратите внимание, что часть «anything» представленных выше выражений не вычисляется, таким образом удаётся избежать любых побочных эффектов вычисления данной части.

Строковые операторы

В дополнение к операторам сравнения, которые могут использоваться со строковыми значениями, оператор (+) позволяет объединить две строки, возвращая при этом третью строку, которая представляет собой объединение двух строк-операндов:

Сокращённый оператор присваивания += также может быть использован для объединения (конкатенации) строк:

Условный (тернарный) оператор

Условный оператор является единственным оператором JavaScript, который использует три операнда. Оператор принимает одно из двух значений в зависимости от заданного условия. Синтаксис оператора:

val1 и val2 обязательно должны что-то возвращать, поэтому в этой конструкции нельзя использовать continue или break

Оператор запятая

Например, если a является двумерным массивом, каждая строка которого содержит 10 элементов, то следующий код с использованием оператора запятая позволяет выполнять одновременное приращение двух переменных. Данный код выводит на экран значения диагональных элементов массива:

Унарные операторы

delete

Оператор delete выполняет удаление объекта, свойства объекта, или элемента массива с заданным индексом. Синтаксис оператора:

Удаление элементов массива

Оператор typeof

Оператор typeof используется одним из следующих способов:

Оператор typeof возвращает строку обозначающую тип невычисленного операнда. Значение operand может быть строкой, переменной, дескриптором, или объектом, тип которого следует определить. Скобки вокруг операнда необязательны.

Предположим, вы определяете следующие переменные:

Оператор typeof возвращает следующие результаты для этих переменных:

Для дескрипторов true и null оператор typeof возвращает следующие результаты:

Для чисел и строк оператор typeof возвращает следующие результаты:

Для свойств оператор typeof возвращает тип значения данного свойства:

Для методов и функций оператор typeof возвращает следующие результаты:

Для встроенных объектов оператор typeof возвращает следующие результаты:

Оператор void

Оператор void используется любым из следующих способов:

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

Приведённый ниже код создаёт гипертекстовую ссылку, которая подтверждает отправку формы при клике на ней пользователем:

Операторы отношения

Оператор отношения сравнивает свои операнды и возвращает результат сравнения в виде булева значения.

Оператор in

Оператор in возвращает true, если указанный объект имеет указанное свойство. Синтаксис оператора:

Некоторые примеры способов использования оператора in :

Оператор instanceof

Оператор instanceof возвращает true, если заданный объект является объектом указанного типа. Его синтаксис:

Приоритет операторов

Приоритет операторов определяет порядок их выполнения при вычислении выражения. Вы можете влиять на приоритет операторов с помощью скобок.

Приведённая ниже таблица описывает приоритет операторов от наивысшего до низшего.

Выражение Результат Двоичное описание
15 & 9 9 1111 & 1001 = 1001
15 | 9 15 1111 | 1001 = 1111
15 ^ 9 6 1111 ^ 1001 = 0110
Таблица 3.7 Приоритет операторов

Тип оператора Операторы
свойство объекта . []
вызов, создание экземпляра объекта () new
отрицание, инкремент !

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

Выражения

Выражением является любой корректный блок кода, который возвращает значение.

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

Код 3 + 4 является примером выражения второго типа. Данное выражение использует оператор «+» для сложения чисел 3 и 4 без присваивания переменной полученного результата 7.

Все выражения в JavaScript делятся на следующие категории:

Основные выражения

Базовые ключевые слова и основные выражения в JavaScript.

Оператор this

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

Предположим, функция validate выполняет проверку свойства value некоторого объекта; задан объект, а также верхняя и нижняя граница величины данного свойства:

Вы можете вызвать функцию validate для обработчика события onChange для каждого элемента формы, используя this для указания на элемент формы, как это показано в следующем примере:

Оператор группировки

Упрощённый синтаксис создания массивов и генераторов

[for (x of y) x] Упрощённый синтаксис для массивов. (for (x of y) y) Упрощённый синтаксис для генераторов.

Упрощённые синтаксисы существуют во многих языках программирования и позволяют вам быстро собирать новый массив, основанный на существующем. Например:

Левосторонние выражения

Значениям слева назначаются значения справа.

Вы можете использовать оператор new для создания экземпляра объекта пользовательского типа или одного из встроенных объектов. Используйте оператор new следующим образом:

super

Ключевое слово используется, чтобы вызывать функции родительского объекта. Это полезно и с классами для вызова конструктора родителя, например.

Оператор расширения

Оператор расширения позволяет выражению расширяться в местах с множеством аргументов (для вызовов функций) или множестве элементов (для массивов).

Похожим образом оператор работает с вызовами функций:

Источник

admin
Делаю сам
Adblock
detector