Почему typeof null === 'object'?

    Все JavaScript-программисты давно привыкли к тому, что typeof null === 'object'; // true, хотя фактически null — примитивное значение. Многие знают, что это баг, и лично Брэндан Айк это признает. Этот баг, вероятно, никогда не будет исправлен из-за необходимости сохранения обратной совместимости существующего кода с новыми версиями языка.

    Интересна история того, как же это получилось. Она восходит корнями к первой версии языка, а именно — к тому факту, что значения переменных хранились в 32-битных ячейках в следующем формате:
    29-31 бит: само значение;
    1-3 бита: метка типа данных;

    Было всего пять вариантов метки типа:
    000: object;
    1: integer;
    010: double;
    100: string;
    110: boolean;

    Соответственно, если младший бит был равен единице, то оставшийся 31 бит интерпретировался как integer. Если 0 — то тип определялся в зависимости от значения следующих двух бит.

    Также было два специальных зарезервированных значения:

    undefined (JSVAL_VOID) — целое –230
    null (JSVAL_NULL) — указатель на NULL (machine code NULL pointer), то есть, метка объекта и ссылка на то, что его численное представление равно нулю.

    Так и вышло, что typeof стал определять null как object — он проверял метку типа, которая сообщала ему, что null — это не что иное, как object.

    via

    Похожие публикации

    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 21

      0
        0
        Да, это перевод. А если уже опубликовал его как пост, теперь плашечку «перевод» поставить никак нельзя?
          0
          Нельзя, вроде.
            +5
            И даже в хаб «Переводы» (вроде, был такой) добавить не получается. Что ж, прошу прощения у читателей.
              0
              Можно написать в тех.поддержку, были прецеденты, когда они меняли тип статьи.
        0
        сейчас принцип организации памяти js другой? Иначе не ясно почему тип string как таковой в js не имеет ограничения по длине. Обясните.
          –2
          Полагаю, в разных движках вполне может быть разный принцип организации памяти.
          string в js — это, грубо говоря, упорядоченный набор символов, каждый из которых представлен в UTF-8. Конец строки обозначается специальным символом EOS (End of string).
          Вот, у каждого символа младшими битами были 100. У каждого символа, а не у всей строки.
            +1
            Вот только не UTF-8, а UTF-16

            www.ecma-international.org/ecma-262/5.1/#sec-8.4
              +2
              Зачем же у каждого символа? У указателя на строку младшими битами были 100. А символы в строке без изменений.
                0
                Спасибо. Да, так логичнее.
                  0
                  У указателя биты? Какой-то пустой расход памяти, если младшие биты у указателя фиксированы.
                    0
                    Выравнивание же. Они бы были нулевыми иначе.
                      0
                      Помеченные указатели (tagged pointers) техника старая как мир. Основывается она на том, большинство распределителей памяти и так выделяют выровненную память и указатели оказываются кратными какой-нибудь степени двойки. Делается это по разным причинам, зависящим от конкретного аллокатора, от фундаментального желания гарантировать правильное выравнивание для данных, которое CPU удовлетворит, до желания уменьшить какие-то внутренние структуры данных. glibc например гарантирует выравнивание на 8 (или даже на 16 на 64-битной системе) для памяти, т.е. младшие 3 бита указателей возвращаемых mallocом всегда 0. (другое дело, что malloc для реализации кучи в VM лучше не использовать, но это другая история). Разумеется это привносит определенную фрагментацию в кучу, но практика показывает, что она не так уж и страшна.
                +5
                'use strict 2' какой-нибудь?
                  0
                  'use version es2016' ?)
                  0
                  удалено
                    0
                    Просто баг. Null определяется, как object, при этом для undefined обработка сделана была корректна, он не определяется же как целое.
                      +7
                      >>> Этот баг, вероятно, никогда не будет исправлен из-за необходимости сохранения обратной совместимости существующего кода с новыми версиями языка.

                      Ну и зря. Наоборот, периодически полезно устраивать в языках несовместимые изменения, чтобы неподдерживаемый код «умирал» естественной смертью.
                      Если код нужен, его починят. Если код не нужен, нафиг такой код.

                      Другой вопрос, а что ДОЛЖЕН возвращать typeof null?
                        +2
                        очевидно, что как и в случае в undefined — null
                          +2
                          >>>Ну и зря. Наоборот, периодически полезно устраивать в языках несовместимые изменения, чтобы неподдерживаемый код «умирал» естественной смертью.

                          Python, который уже лет 5 переезжает на 3.x и волевым решением запретивший 2.8, с данным мнением согласен :)
                          Java смотрит с презрением.
                            +1
                            Вообще-то в 9 случаях их 10 умирает «обновлённый язык». В лучшем случае, если очень повезёт лет так через 10 люди постепенно переходят на новую версию — если всё это время разработчики с нечеловеческими усилиями стремятся всех пересадить на новую версию. См. Perl6, PHP6, Python3. Из более ранних примеров: Algon/Pascal/Modula-2/Oberon — «очистка языка» привела к тому, что он, может и стал лучше, но однозначно из категории «популярный и широкоизвестный» перекочевал в категорию «прикольный курьёз».

                            Разработчики Javascript'ы выбрали единственный разумный вариант: сделать так, чтобы разработчик мог выбирать диалект. Посмотрим как у них получится.

                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                          Самое читаемое