предисловие
Многие друзья считают, чтоjavaScript
Очень просто, следующая строкаjavaScript
Код может заставить вас сомневаться в жизни.
(!(~+[])+{})[--[~+""][+[]]*[~+[]] + ~~!+[]]+({}+[])[[~!+[]]*~+[]]
Маленькие друзья научились, и в будущем, если вы встретите каких-то неразумных людей, которые делают вас неразумными, отправьте ему этот код.
Так почему же этот код выводит sb?
На самом деле, этот код исследует некоторые основные принципы преобразования типов js.
Первое знание, которое нужно применить, это приоритет оператора js.Поскольку такая длинная операция ослепительна, мы должны сначала разделить ее на n небольших сегментов в соответствии с приоритетом, а затем разбить каждый.
1, приоритет операторов js
Порядок приоритета следующий:
Приоритет от высокого к низкому:
Согласно этому правилу, мы разделяем эту строку операций на следующие 16 подвыражений:
Операторы помечены красным.Одна вещь, которую вы можете не осознавать, это то, что квадратные скобки [] также являются оператором, который используется для доступа к элементам массива по индексу, а также может обращаться к подсимволам строк, что похоже на метод charAt, например as: 'abcd'[1] // Возвращаем 'b'. И скобки имеют наивысший приоритет.
Следующее, что нужно использовать, этоjavascript
Теперь, когда знания о преобразовании типов получены, давайте сначала поговорим об обстоятельствах, при которых необходимо выполнять преобразование типов. Когда типы операндов с обеих сторон оператора несовместимы или не относятся к примитивным типам (также называемым примитивными типами), требуется преобразование типов.
Давайте быстро напомним.JavaScript, существует два типа значений: примитивные значения(primitives)
и стоимость объекта(objects)
.
- Примитивные значения: undefined, null, логические значения, числа и строки.
- Все остальные значения имеют тип object, включая массивы и функции.
2. Преобразование типов
(1) Сначала разделим категории по операторам:
-
Знак минус - и знак умножения * определенно являются математическими операциями, поэтому операнды необходимо преобразовать в числовой тип.
-
Знак плюс + может быть конкатенацией строк или математической операцией, поэтому его можно преобразовать в число или строку.
-
Унарные операции, такие как +[], имеют только один операнд и преобразуются в числовой тип.
(2) Давайте рассмотрим правила конвертации ниже.
(2).1 Для непримитивных типов преобразуйте значение в примитивный тип с помощью ToPrimitive():
ToPrimitive(ввод, PreferredType?)
Необязательный параметр PreferredType — число или строка. Возвращаемое значение — любое примитивное значение.Если PreferredType имеет значение Number, порядок выполнения следующий:
Если ввод примитивный, верните
В противном случае вводом является Объект. Вызовите obj.valueOf(). Если результат примитивен, возврат.
В противном случае вызовите obj.toString().Если результат примитивен, верните
В противном случае выбросить TypeError
Если PreferredType — String, шаги 2 и 3 меняются местами, если PreferredType — нет, экземпляру Date присваивается значение String, а остальным — Number.
(2).2 Преобразование значения в число с помощью ToNumber()
Преобразуйте значение в число через ToNumber(), посмотрите непосредственно на таблицу ECMA 9.3.
параметр | результат |
---|---|
undefined | NaN |
null | +0 |
Логическое значение | true преобразуется в 1, false преобразуется в +0 |
номер | Преобразование не требуется |
нить | Преобразует строку в число. Например, "324" преобразуется в 324. |
Если входное значение является объектом, он сначала вызовет ToPrimitive(obj, Number) для преобразования объекта в примитивное значение, а затем вызовет ToNumber() для преобразования примитивного значения в число.
(2).3 Преобразование значения в строку с помощью ToString()
Преобразуйте значение в строку через ToString(), см. непосредственно таблицу ECMA 9.8.
параметр | результат |
---|---|
undefined | "undefined" |
null | "null" |
Логическое значение | "правда или ложь" |
номер | Числа в виде строк, например "1,765" |
нить | Преобразование не требуется |
Если входное значение является объектом, он сначала вызовет ToPrimitive(obj, String) для преобразования объекта в значение-примитив, а затем вызовет ToString() для преобразования значения-примитива в строку.
Правил так много, давайте потренируемся и выполним этот волшебный код шаг за шагом в соответствии с подвыражениями, которые мы разделили выше. Начать работу~
Сначала взгляните на простейшее подвыражение 16: +[]
Есть только один операнд [], который необходимо преобразовать в число.Согласно вышеприведенному правилу 2, [] — это массив объектного типа, то есть объект. Таким образом, вы должны сначала вызвать toPrimitive для преобразования в исходный тип, а PreferredType — это число Этот параметр указывает тип, который более «подвержен» преобразованию, который здесь должен быть числом. Затем сначала вызовите метод valueOf массива, и массив вызовет valueOf, чтобы вернуть себя, как показано ниже:
В это время мы получаем пустую строку "", которая еще не закончилась, см. описание правила 2 выше, продолжаем вызывать toNumber, и преобразовывать его в числовой тип, следующим образом:Готово! Подвыражение 16 преобразуется, +[] и, наконец, получается 0.
Посмотрите на подвыражение 15: [~+""]
Пустой строке "" предшествуют два унарных оператора, но операнд по-прежнему только один, поэтому последний тип, в который нужно преобразовать, — это число. Посмотрите на правило 2. Вызовите toNumber для пустой строки и получите 0. Далее ~, что это за штука? Это побитовый оператор, который можно записать как отрицание числа, а затем вычитание единицы, поэтому ~0 равно -1.
Не забывайте, это подвыражение заключено в квадратные скобки, поэтому конечное значение равно [-1], что представляет собой массив только с одним элементом -1.
Далее смотрим подвыражение 13. Оно простое.Заполняем значения, полученные из 15 и 16, и становится так: --[-1][0], берем 0-й элемент массива, и затем уменьшите его, результат Для -2 это не так просто!
идет вверх, подвыражение 14: [~+[]]
На самом деле применение принципов 15 и 16 совершенно очевидно. Ответ [-1]
Продолжаем находить подвыражение 9. На данный момент оно стало таким: -2*[-1], что немного отличается, но это не имеет значения, мы по-прежнему следуем правилам.Оператор - знак умножения *, конечно, это математическая операция, тогда следующий [-1] должен быть преобразован в число, что аналогично методу нахождения 16. Процесс выглядит следующим образом:
①Вызовите toPrimitive и убедитесь, что он относится к объектному типу.
②Вызов valueOf, возврат самого себя[-1]
③Поскольку это не примитивный тип, продолжайте вызывать toString и возвращайте "-1"
④"-1" является примитивным типом, затем вызовите toNumber и верните -1
⑤ Умножить на -2, вернуть 2
Подключение 10:! ~~ + [], нечего сказать, ответ 1, а затем один доллар справа налево.
С 9 и 10 мы приходим к подвыражению 4, которое теперь выглядит так: 2+1, ну больше не буду говорить.
Продолжайте смотреть на выражение 7: !(~+[]), ~+[]=-1, это уже известно из предыдущего, так что же такое !-1? Я хочу поговорить об этом восклицательном знаке здесь. Он означает логическое отрицание и преобразует выражение в логический тип. Правила преобразования такие же, как принципы истинности и ложности js, за которыми следуют числа. За исключением 0, это является ложным. Со строками все, кроме пустых строк, являются ложными. !-1 здесь, конечно, ложно.
Следующее выражение 3: false+{} немного критично. Логическое значение плюс объект, то этот {} должен быть сначала преобразован в примитивный тип, процесс выглядит следующим образом:
①Вызовите toPrimitive и убедитесь, что он относится к объектному типу.
②вызвать valueOf, вернуть себя{}, ③Не примитивный тип, вызовите toString, верните "[object Object]"
④false добавляется к "[object Object]", false сначала преобразуется в строку "false"
⑤Добавление результата "false[object Object]"
Зная выражения 3 и 4, мы можем посмотреть на выражение 1, которое выглядит так: "false[object Object]"[3], потому что this[] может принимать подсимволы строк, например charAt, так что мы получаем результат " с"
После описанного выше сложного процесса у нас получился символ "s", который является левой половиной картинки, и оставшаяся "b", можно проработать тот же принцип, я не буду демонстрировать их здесь по одному, оставьте так тебе давай потренируемся~
Оглядываясь назад, этот процесс на самом деле не сложен, но есть некоторые вещи, которые необходимо повторить.Пока вы освоите приоритет операций, вы можете разложить большие строки на маленькие строки, а затем использовать знание преобразования типов для обработки их один за другим. Как, ты все еще чувствуешь себя потрясающе, когда видишь это?
Точно так же китайские иероглифы также состоят из этого, по той же причине, что и английские.
Ссылаться на
Блог Woohoo.cn на.com/self shipping/AR… Знайте. Baidu.com/question/43…