Извините за титульную вечеринку, в JavaScript никогда не бывает странных событий, я просто хочу разобраться с запутанными выражениями в JavaScript и принципом, лежащим в их основе.
Например, произнесите результаты следующих выражений:
1 + '1'1 - '1''2' + '2' - '2'[] + []{} + {}[] + {}{} + [][] + {} === {} + []{} + [] === [] + {}[+false] + [+false] + [+false][+false] + [+false] + [+false] - [+false]'1' == trueparseInt('infinity') == 0 / 01 < 2 < 33 > 2 > 1isNaN(false)isNaN(null)[[][[]]+[]][+[]][++[+[]][+[]]]
Если вы хотите узнать правильный ответ, вставьте выражение в консоль браузера и выполните его.
Следующее содержание должно объяснить принцип, по которому получаются результаты этих выражений.
Ключом к решению вышеуказанных проблем является понимание трех моментов:
- Использование оператора и приоритет
- Правила преобразования типов данных для операндов в контексте операторов
- особые случаи в грамматике
+оператор
+В JavaScript есть три функции:
- Строка подключения:
var result = 'Hello' + 'World' - Вычислите сумму чисел:
var result = 1 + 2 - Как унарный оператор:
+variable
в выражении+оператор, объект, над которым работает оператор (в приведенном выше примереHello,World,1,2) именованный операнд (операнд)
Один юань+Правила работы оператора:ToNumber(ToPrimitive(operand))То есть преобразовать любой тип шрифта в цифровой тип.
Когда типы данных операндов несовместимы, они будут преобразованы в соответствии со следующими правилами:
- Если хотя бы один операнд имеет объектный тип данных (
object), вам нужно преобразовать его в базовый тип (primitive), то есть строка, число или логическое значение- если объект
Dateпиши, потом звониtoString()метод - В противном случае позвоните сначала
valueOf()метод - если
valueof()Метод не существует или не возвращает базовый тип, затем вызовитеtoString() - Когда массив преобразуется в базовый тип, JavaScript использует
join(',')метод - Простые объекты 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===называется тождественным оператором (тождественным оператором),==Вызывается оператором равенства (оператором равенства). Из-за нехватки места здесь мы просто говорим о последнем для темы.
если==Типы данных операндов операторов разные:
- Если операнд
null, а другой операндundefined, они равны - Если один операнд является числовым типом, а другой — строковым типом, то преобразуйте строковый тип в числовой тип и сравните
- Если операнд имеет тип Boolean, то поставьте
trueпревращается в 1,falseПреобразовать в 0 для сравнения - Если один операнд является объектом, а другой операнд является числом или строкой, то преобразуйте объект в примитивный тип и сравните
- Согласно приведенным выше правилам, при вычислении выражения
'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] ]. Если это все еще не ясно, три части слева направо:
[ [][[]]+[] ][0][ ++[0][0] ]
Смотрим первую часть+передний[][[]]операнд, первый[]является пустым массивом, и следующее[[]]является средством доступа к свойству (оператор-член) в средстве доступа к свойству[]будет приведен к строковому типу, и конечным результатом будет пустая строка'', поэтому окончательный результат первого операнда на самом деле[][''], то естьundefined, и потому что+правила оператора, в конечном счете[][[]]+[]Результатом выражения является строка'undefined', то результатом текущего выражения будет['undefined'][0][++[0][0]],Прямо сейчас'undefined'[++[0][0]]
Далее приступаем к третьей части:[++[0][0]], я уже знаю член оператора[]имеет более высокий приоритет, чем оператор приращения++, так что о выражении++[0][0], нам нужно сначала вычислить[0][0],оказаться0, а затем вычислить++0результат1
Таким образом, окончательное выражение превращается в'undefined'[1], окончательный результат'n'
Эта статья также опубликована в моей колонке Zhihu в то же время.Автостопом по передовым технологиямвверх, приветствую всех, чтобы обратить внимание
Справочная статья
- JavaScript addition operator in details
- The legend of JavaScript equality operator
- What is the explanation for these bizarre JavaScript behaviours mentioned in the 'Wat' talk for CodeMash 2012?
- Why is {} + {} no longer NaN in Chrome console?
- Why does JavaScript handle the plus and minus operators between strings and numbers differently?
- Operator precedence
- Member operators
- isNaN()