Если вы можете ответить да, то поздравляю, вы можете объезжать
предисловие
Некоторые люди скажут, что эта проблема очень странная, если она поставлена на другие языки, если она может выводить true, это, наверное, ад, но не говорите этого, ее действительно можно поставить в js. Недавно в твиттере одного человека был задан вопрос:
- Вопрос: Может ли (a==1 && a==2 && a==3) когда-либо быть истинным?
- Ответ: да
В этом посте я объясню, как работает этот код:
const a = {
num: 0,
valueOf: function() {
return this.num += 1
}
};
const equality = (a==1 && a==2 && a==3);
console.log(equality); // true
Вы можете открыть браузер Chrome, затем открыть режим разработчика, ввести этот код в консоли, вы можете увидеть вывод ([windows]: Ctrl + Shift + J [mac]: Cmd + Opt + J)
В чем хитрость?
На самом деле нет, в js есть два понятия:
- неявное преобразование
- функция valueOf объекта
неявное преобразование
Примечание: в этом вопросе мы используем == вместо === В js == представляет собой равенство, а не конгруэнтность, поэтому возникает проблема неявного преобразования переменных. Это означает, что результат будет более вероятным, чем мы ожидали. По неявному преобразованию js действительно много статей, рекомендую следующие блоги, если хотите узнать больше, можете кликнуть туда:
valueOf
JavaScript предоставляет способ преобразования объектов в примитивные значения: Object.prototype.valueOf() по умолчанию возвращает вызываемый объект.
Возьмем пример:
const a = {
num: 0
}
Мы можем использовать метод valueOf для вышеуказанного объекта, и он вернет объект.
a.valueOf();
// {num: 0}
Разве это не круто, мы можем использовать typeOf для проверки типа этого вывода:
typeof a.valueOf();
// "object"
Чтобы сделать valueOf более удобным для преобразования объекта в примитивное значение, мы можем его переписать, другими словами, мы можем использовать valueOf для возврата строки, числа, логического значения и т. д. вместо объекта мы можем видеть следующий код:
a.valueOf = function() {
return this.num;
}
Мы переопределили родной метод valueOf(), который возвращает a.num при вызове valueOf. Затем мы запускаем следующее:
a.valueOf();
// 0
Мы получаем 0, что имеет смысл, поскольку 0 — это значение, присвоенное a.num. Затем мы можем сделать несколько тестов:
typeof a.valueOf();
// "number"
a.num == a.valueOf()
// true
очень хороший,Но почему это важно?
Это важно, потому что когда вы столкнулись с оператором равенства между двумя различными типами, JS бросает его - он пытается бросить операнды на подобные типы.
В нашем вопросе:(a==1 && a==2 && a==3)JavaScript попытается преобразовать объект в числовой тип для сравнения.Когда объект, который нужно преобразовать, является Object, JavaScript вызовет метод valueOf().
Поскольку мы изменили метод valueOf(), можем ли мы сделать следующее:
a == 0
// true
Мы сделали это с невероятной легкостью.
Теперь все, что нам нужно сделать, это изменить значение a каждый раз, когда мы его вызываем.
К счастью, в JavaScript есть+=символ.
+=Этот оператор может легко изменить значение, приведем простой пример:
let b = 1
console.log(b+=1); // 2
console.log(b+=1); // 3
console.log(b+=1); // 4
Как видите, мы увеличиваем нашу переменную каждый раз, когда используем оператор присваивания сложения.
Таким образом, мы можем применить эту концепцию к valueOf().
a.valueOf = function() {
return this.num += 1;
}
Каждый раз, когда мы вызываем valueOf, он увеличивает переменную на 1 и возвращает ее нам.
С этим изменением запустим следующий код:
const equality = (a==1 && a==2 && a==3);
console.log(equality); // true
Вот как это работает.
Запомните следующие два момента:
- Используя оператор равенства, js будет выполнять принудительное преобразование типов.
- Каждый раз, когда наш объект вызывает valueOf(), его значение увеличивается на 1.
Так что при сравнении мы каждый раз получаем истину.
- Дополнить процесс работы второй точки
a == 1 ->
a.valueOf() == 1 ->
a.num += 1 == 1 ->
0 += 1 == 1 ->
1 == 1 -> true
a == 2 ->
a.valueOf() == 2 ->
a.num += 1 == 2 ->
1 += 1 == 2 ->
2 == 2 -> true
a == 3 ->
a.valueOf() == 3 ->
a.num += 1 == 3 ->
2 += 1 == 3 ->
3 == 3 -> true
Суммировать
Спасибо, что посмотрели этот небольшой эксперимент, надеюсь, вы сможете чему-то научиться из него, а друзья, которым интересно, тоже могут зайти на мойgithubНажмите звездочку, ваша поддержка является движущей силой для моей непрерывной работы, спасибо! ! !