Перлы языка JavaScript: строки, массивы и непонятные моменты

6
7102
Добавить в избранное

Возвращаясь к «косякам», JavaScript строки, массивы и разномастные формулы также оказались под прицелом Брайана Лера в его лекции «WTFJS».

JavaScript строки

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

Минимальное значение больше нуля

Number.MIN_VALUE – наименьшее число, которое больше нуля:

Объяснение:

Number.MIN_VALUE = 5e-324, т. е. наименьшее положительное число, которое может быть представлено с точностью до float – как можно ближе к нулю.

Теперь самое маленькое значение – Number.NEGATIVE_INFINITY, хотя оно не является действительно числовым в строгом смысле.

Функция – это не функция

Ошибка, присутствующая в V8 v5.5 или ниже (Node.js <= 7).

Как насчет такого? Посмотрите на эти JavaScript строки:

Объяснение:

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

Добавление массивов

Что произойдет, если вы попытаетесь вывести сумму двух массивов?

Объяснение:

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

Массив с плавающей запятой

Вы создали массив с четырьмя пустыми элементами. Несмотря на это, вы получите 3 элемента из-за плавающей запятой:

Объяснение:

Трейлинг-запятые (также называемые «финальными запятыми») могут быть полезны при добавлении новых элементов, параметров или свойств в код JS. Хотите добавить новое свойство? Просто объявите новую строку без изменения предыдущей, если данная строка уже использует запятую. Такой подход значительно упростит работу, ведь само редактирование кода станет менее проблематичным.

Равномерность массива – монстр

Равномерность массива – это настоящий монстр в мире JS. Смотрите сами:

Объяснение:

Вы должны быть очень осторожны! Это сложный пример, но он описан в спецификации 7.2.13. Абстрактное сравнение равенства.

undefined и Number

Если мы не передадим аргументы в конструктор Number, то получим 0. Значение undefined присваивается формальным аргументам, когда нет реальных, поэтому вполне ожидаемо, что Number без аргументов принимает значение undefined. Если же это неопределенность, мы однозначно получим результат в виде NaN.

Объяснение:

Согласно спецификации:

  1. Если аргументы этой функции не были переданы, пусть n будет равно +0.
  2. Иначе что произойдет с n? ToNumber (value).
  3. В случае с undefined, ToNumber (undefined) должен возвращать NaN.

Также рекомендуем изучить соответствующие разделы:

parseInt – плохой парень

parseInt славится своими причудами:

Объяснение:

Это происходит потому, что parseInt будет производить посимвольный синтаксический разбор до тех пор, пока не наткнется на символ, которого он не знает. f в ‘f *ck’ является шестнадцатеричной цифрой 15.

Парсинг Infinity в данной ситуации представляет собой нечто подобное:

Также будьте осторожны нулевым значением:

Объяснение:

Да, JavaScript строки нередко ведут себя крайне странно: привыкайте. Приведенный выше пример конвертирует значение null в строку «null» и пытается его преобразовать. В интервале от 0 до 23 нет цифр, которые он может преобразовать, поэтому он возвращает NaN.

Не забывайте и о восьмеричных значениях:

Объяснение:

Если входная строка начинается с «0», то все зависит от поддержки ECMAScript 5, что возможно не во всех современных браузерах.

parseInt всегда конвертирует ввод в строку:

Математика с true и false

Давайте сгенерируем небольшой математический пример:

Хммм…

Объяснение:

Мы можем закреплять за значениями числа с помощью конструктора Number. Совершенно очевидно, что true будет равно единице:

Оператор унарного плюса пытается преобразовать его значение в число. Он может преобразовывать JavaScript строки, с помощью которых реализовано представление целых чисел, и float. А еще, как видим, это могут быть значения, отличные от строки: true, false и null. Если он не может разобрать конкретное значение, в результате будет выдан NaN. Это означает, что мы можем все упростить:

Когда вы выполняете сложение или умножение, вызывается метод ToNumber. Согласно спецификации, этот метод возвращает:

  1. Если аргумент равен true, возвращается 1.
  2. Если аргумент false, возвращается +0.

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

Соответствующие разделы по теме:

HTML-комментарии возможны в JavaScript

Вы удивитесь, но <!— (который известен как комментарий HTML) является допустимым комментарием в JavaScript.

Объяснение:

Впечатлены? HTML-подобные комментарии предназначены для того, чтобы браузеры, которые не понимают тег <script>, быстрее загибались. К таким можно отнести Netscape 1.x, который давно перестал быть популярным. Поэтому нет смысла добавлять HTML-комментарии в теги скриптов.

Поскольку Node.js основан на движке V8, комментарии, подобные HTML, также поддерживаются средой выполнения Node.js. Более того, они являются частью спецификации:

NaN не является числом

Тип NaN – это число:

Объяснения того, как работают операторы typeof и instanceof:

[] И null – объекты

Объяснение:

Поведение оператора typeof подробно разъясняется в этом разделе спецификации:

Согласно спецификации, оператор typeof возвращает JavaScript строки в соответствии с таблицей 35: typeof Operator Results. Для нулевых, обычных и многих других объектов, которые не реализовывают [[Call]], он возвращает строку «object».

Тем не менее, вы можете проверить тип объекта с помощью метода toString.

Магически увеличивающиеся числа

Объяснение:

Это вызвано стандартом IEEE 754-2008 для двоичной системы с плавающей запятой. В данном масштабе все округляется до ближайшего четного числа. Прочитайте больше:

Точность 0.1 + 0.2

Известная шутка. Добавление 0.1 и 0.2 является смертельно точным:

Объяснение:

Ответ на вопрос «Связана ли эта проблема с плавающей запятой?» на StackOverflow:

Константы 0.2 и 0.3 в вашей программе также будут приближаться к их истинным значениям. Бывает, что ближайший double к 0.2 больше, чем рациональное число 0.2, но ближайший double к 0.3 меньше рационального числа 0.3. Сумма 0.1 и 0.2 больше, чем рациональное число double и, следовательно, не согласуется с константой в вашем коде.

Эта проблема настолько известна, что есть даже сайт под названием 0.30000000000000004.com. Такое встречается в каждом языке, который использует математику с плавающей запятой, а не только JavaScript.

Патч-номера

Вы можете добавить свои собственные методы для обертки таких объектов, как Number или String.

Объяснение:

Очевидно, вы можете экстендить объект Number, как и любой другой объект в JavaScript. Однако не рекомендуется это делать, если поведение определенного метода не является частью спецификации. Вот список свойств Number:

Сравнение трех чисел

Объяснение:

Почему так? Ну, проблема в первой части выражения. Вот как это работает:

Мы можем исправить это с помощью оператора больше или равно (> =):

Подробнее о реляционных операторах в спецификации:

Смешная математика

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

Объяснение:

Что происходит в первых четырех примерах? Вот небольшая таблица, чтобы понять принцип добавления в языке JavaScript:

Как насчет других примеров? Методы ToPrimitive и ToString неявно вызываются для [] и {} перед добавлением. Подробнее о процессе оценки в спецификации:

JavaScript строки не являются экземплярами String

Объяснение:

Конструктор возвращает строку:

Попробуем с новым кодом:

JavaScript строки – объект? Что это?

Дополнительная информация о конструкторе String в спецификации:

Интересуетесь веб-разработкой?

Подпишитесь на нашу рассылку, чтобы получать больше интересных материалов:

И не беспокойтесь, мы тоже не любим спам. Отписаться можно в любое время.




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

  1. «…Это происходит потому, что parseInt будет производить посимвольный синтаксический разбор до тех пор, пока не наткнется на символ, которого он не знает. f в ‘f *ck’ является шестнадцатеричной цифрой 15..»

    А ‘e’ в ‘e*ck’ — шестнадцатеричная цифра 14, почему тогда в ее случае получается NaN?

    1. Там кириллическая «е»

  2. «Просто объявите новую строку без изменения предыдущей»
    это некорректный перевод фразы:
    «simply add a new line without modifying the previously last line»
    правильнее так:
    «Просто добавьте новую строку без изменения предыдущей»
    так как речь идет о строке кода, а не о строковой переменной

Добавить комментарий