Извините за титульную вечеринку, в 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)
[[][[]]+[]][+[]][++[+[]][+[]]]
Если вы хотите узнать правильный ответ, вставьте выражение в консоль браузера и выполните его.
Следующее содержание должно объяснить принцип, по которому получаются результаты этих выражений.
Ключом к решению вышеуказанных проблем является понимание трех моментов:
- Использование оператора и приоритет
- Правила преобразования типов данных для операндов в контексте операторов
- особые случаи в грамматике
+
оператор
+
В 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()