Книга странных событий JavaScript

внешний интерфейс JavaScript Chrome

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

Например, произнесите результаты следующих выражений:

  • 1 + '1'
  • 1 - '1'
  • '2' + '2' - '2'
  • [] + []
  • {} + {}
  • [] + {}
  • {} + []
  • [] + {} === {} + []
  • {} + [] === [] + {}
  • [+false] + [+false] + [+false]
  • [+false] + [+false] + [+false] - [+false]
  • '1' == true
  • parseInt('infinity') == 0 / 0
  • 1 < 2 < 3
  • 3 > 2 > 1
  • isNaN(false)
  • isNaN(null)
  • [[][[]]+[]][+[]][++[+[]][+[]]]

Если вы хотите узнать правильный ответ, вставьте выражение в консоль браузера и выполните его.

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

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

  1. Использование оператора и приоритет
  2. Правила преобразования типов данных для операндов в контексте операторов
  3. особые случаи в грамматике

+оператор

+В JavaScript есть три функции:

  1. Строка подключения:var result = 'Hello' + 'World'
  2. Вычислите сумму чисел:var result = 1 + 2
  3. Как унарный оператор:+variable

в выражении+оператор, объект, над которым работает оператор (в приведенном выше примереHello,World,1,2) именованный операнд (операнд)

Один юань+Правила работы оператора:ToNumber(ToPrimitive(operand))То есть преобразовать любой тип шрифта в цифровой тип.

Когда типы данных операндов несовместимы, они будут преобразованы в соответствии со следующими правилами:

  • Если хотя бы один операнд имеет объектный тип данных (object), вам нужно преобразовать его в базовый тип (primitive), то есть строка, число или логическое значение
    1. если объектDateпиши, потом звониtoString()метод
    2. В противном случае позвоните сначалаvalueOf()метод
    3. еслиvalueof()Метод не существует или не возвращает базовый тип, затем вызовитеtoString()
    4. Когда массив преобразуется в базовый тип, JavaScript используетjoin(',')метод
    5. Простые объекты Javascript{}Результат преобразования[object Object]
  • После преобразования, если хотя бы один операнд имеет тип строка, то другой операнд также необходимо преобразовать в строку типа, а затем выполнить операцию конкатенации
  • В остальных случаях оба операнда преобразуются в числовые типы и выполняется операция сложения
  • Если оба операнда являются примитивными типами, оператор определяет, что по крайней мере один из них имеет тип string, и выполняет операцию конкатенации. Все остальные случаи преобразуются в числа и суммируются

Итак, в соответствии с приведенными выше правилами, мы можем интерпретировать:

  • 1 + '1'Результат'11', поскольку один из операндов является строкой, другой операнд также преобразуется в строку и выполняется операция конкатенации строк
  • [] + []Результат''Пустая строка, так как массив является типом объекта, результатом преобразования в базовый тип является пустая строка, и после конкатенации она остается пустой строкой.
  • [] + {}Результат[object Object], так как операнд имеет отношение типа объекта, оба операнда должны быть преобразованы в базовый тип,[]Результат преобразования в базовый тип'',{}Результат преобразования в базовый тип[object Object], результат окончательной конкатенации строк по-прежнему[object Object]

Далее поговорим о примечательных случаях

  • {} + []Результат0. Потому что в этом выражении начало{}Не пустой литерал объекта, а рассматриваемый как пустой блок кода. На самом деле значение этого выражения равно+[]результат, то естьNumber([].join(',')), который0

  • Еще незнакомец{} + {}Это выражение, выполненное в разных браузерах, даст разные результаты. Согласно приведенному выше примеру, мы можем аналогичным образом сделать вывод, что значение этого выражения на самом деле равно+{}значение, то есть конечный результатNumber([object Object]),Прямо сейчасNaN. В IE 11 результат тот же, но если вы выполните его в Chrome, вы получите результат[object Object][object Object].

согласно сОтветы на StackoverflowЭто связано с тем, что инструменты разработки Chrome неявно добавляют круглые скобки к выражениям при выполнении кода.(), код, который фактически выполняется,({} + {}). Если вы выполняете в IE 11({} + {}), ты получишь[object Object][object Object]результат

  • Хотя мы разъяснили выше[] + {}Результат[object Object],а также{} + []Результат0, но если вы сравните их:[] + {} === {} + []результат будетtrue. потому что право{}следовать в===После отношения оно больше не считается пустым блоком кода, а буквально пустым объектом, поэтому результаты с обеих сторон[object Object]

  • {} + [] === [] + {}Это также неоднозначный результат.Теоретически возвращаемое значение выражения равноfalse, который работает в IE 11, но возвращается в Chrome devtoolstrue, причина все же в том, что выражение помещено в()выполнить в

  • [+false] + [+false] + [+false]Результаты также предсказуемы.+falseРезультатfalseпреобразовать в числа0,Позже[0]снова преобразуется в строку базового типа'0', поэтому окончательный результат выражения'000'

-оператор

несмотря на то что-оператор и+операторы выглядят одинаково, но-У оператора есть только одна функция, то есть вычитание чисел. Он попытается преобразовать нечисловые операнды в числовые типы, если результат преобразованияNaN, то результат выражения можно представить в видеNaN, если все преобразования успешны, выполняется операция вычитания, поэтому

  • 1 - '1'То, что на самом деле выполняется,1 - 1, результат0
  • '2' + '2' - '2'Выражения должны сначала следовать порядку выполнения слева направо,'2' + '2'Реализация конкатенации строк, результат'22',В следующих'22' - '2'Оба операнда при вычислении успешно преобразуются в числа, а результатом является результат вычитания чисел20
  • [+false] + [+false] + [+false] - [+false]Что выражение на самом деле делает, так это'000' - '0', конечным результатом является число0

==оператор

в JavaScript===называется тождественным оператором (тождественным оператором),==Вызывается оператором равенства (оператором равенства). Из-за нехватки места здесь мы просто говорим о последнем для темы.

если==Типы данных операндов операторов разные:

  1. Если операндnull, а другой операндundefined, они равны
  2. Если один операнд является числовым типом, а другой — строковым типом, то преобразуйте строковый тип в числовой тип и сравните
  3. Если операнд имеет тип Boolean, то поставьтеtrueпревращается в 1,falseПреобразовать в 0 для сравнения
  4. Если один операнд является объектом, а другой операнд является числом или строкой, то преобразуйте объект в примитивный тип и сравните
  • Согласно приведенным выше правилам, при вычислении выражения'1' == true, сначалаtrueпреобразовать в числа1, в это время в выражении присутствуют как числовые, так и строковые типы, а затем строковый'1'преобразовать в числа1, наконец1 == 1Конечно установлено
  • выражениеparseInt('infinity') == 0 / 0на самом деле судитьNaN == NaN, такое сравнение является частным случаем либо в==сравните еще===В сравнении,NaNничему не равен, или пока любой операндNaN, то выражение возвращаетfalse

Более полный==а также===Правила сравнения см.The legend of JavaScript equality operator

оператор сравнения>а также<Он также следует аналогичным правилам: 1. Сначала преобразуйте строки в числа для сравнения, 2. Преобразуйте логические типы в числа для сравнения.

  • в выражении1 < 2 < 3, сначала выполнить1 < 2, результатtrue, но сравниваяtrue < 3процесс, необходимоtrueПреобразование в числовой тип1, финальное сравнение1 < 3, возвращаемое значение равноtrue
  • Точно так же в выражении3 > 2 > 1, окончательное сравнение на самом делеtrue > 1, то есть,1 > 1Конечно возвращаетсяfalse

isNaN

«NaN» — это сокращение от «Not a Number», подумали мы.isNaNЕго можно использовать напрямую, чтобы определить, является ли значение числовым типом, но на самом деле его нельзя использовать. потому чтоisNaNСначала параметр будет принудительно преобразован в числовой тип, а затем будет вынесено решение. Нетрудно объяснить, почемуisNaN(false)а такжеisNaN(null)возвратtrue,потому чтоfalseа такжеnullможет быть успешно преобразован в цифровой0, Таким образом, дляisNaNНапример, это числа

конец

Наконец, мы используем выражение[[][[]]+[]][+[]][++[+[]][+[]]]как конец статьи

В этом выражении три оператора:

  • Оператор-участник:[]
  • Унарный оператор:+
  • Операторы, которые действуют как суммирование или конкатенация строк:+
  • Оператор увеличения:++

По словам операторасписок приоритетов, мы можем определить приоритет операторов следующим образом:[]> унарный оператор+ > ++ > +

Таким образом, в соответствии с приоритетом мы можем сначала вычислить выражение+[]часть и замените эту часть выражения результатом вычисления:[[][[]]+[]][0][++[0][0]]

Далее мы разделяем выражение на три части:[ [][[]]+[] ] [0] [ ++[0][0] ]. Если это все еще не ясно, три части слева направо:

  1. [ [][[]]+[] ]
  2. [0]
  3. [ ++[0][0] ]

Смотрим первую часть+передний[][[]]операнд, первый[]является пустым массивом, и следующее[[]]является средством доступа к свойству (оператор-член) в средстве доступа к свойству[]будет приведен к строковому типу, и конечным результатом будет пустая строка'', поэтому окончательный результат первого операнда на самом деле[][''], то естьundefined, и потому что+правила оператора, в конечном счете[][[]]+[]Результатом выражения является строка'undefined', то результатом текущего выражения будет['undefined'][0][++[0][0]],Прямо сейчас'undefined'[++[0][0]]

Далее приступаем к третьей части:[++[0][0]], я уже знаю член оператора[]имеет более высокий приоритет, чем оператор приращения++, так что о выражении++[0][0], нам нужно сначала вычислить[0][0],оказаться0, а затем вычислить++0результат1

Таким образом, окончательное выражение превращается в'undefined'[1], окончательный результат'n'

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

Справочная статья