Примечание модератора: Пожалуйста, не поддавайтесь желанию отредактировать код или удалить это уведомление. Образец пробельных символов может быть частью вопроса и поэтому не должен быть изменен без необходимости. Если вы относитесь к лагерю "пробельные символы несущественны", вы можете принять код как есть.
Возможно ли, что (a== 1 && a ==2 && a==3)
может иметь значение true
в JavaScript?
Этот вопрос задали на собеседовании в крупной технологической компании. Это произошло две недели назад, но я все еще пытаюсь найти ответ. Я знаю, что мы никогда не пишем такой код в нашей повседневной работе, но мне интересно.
Если вы воспользуетесь преимуществами how ==
works, вы можете просто создать объект с пользовательской функцией toString
(или valueOf
), которая при каждом использовании изменяет возвращаемое значение таким образом, чтобы оно удовлетворяло всем трем условиям.
const a = {
i: 1,
toString: function () {
return a.i++;
}
}
if(a == 1 && a == 2 && a == 3) {
console.log('Hello World!');
}
Причина, по которой это работает, заключается в использовании оператора свободного равенства. При использовании свободного равенства, если один из операндов имеет тип, отличный от другого, движок попытается преобразовать один из них в другой. В случае объекта слева и числа справа, он попытается преобразовать объект в число, сначала вызвав valueOf
, если он доступен, а если нет, то вызовет toString
. Я использовал toString
в данном случае просто потому, что это то, что пришло мне на ум, valueOf
было бы более логичным. Если бы я вместо этого вернул строку из toString
, движок попытался бы преобразовать строку в число, что дало бы тот же конечный результат, хотя и с немного более длинным путем.
Я не мог'т сопротивляться - другие ответы безусловно, верно, но вы действительно можете'т пройти мимо следующий код:
в
var aᅠ = 1;
var a = 2;
var ᅠa = 3;
if(aᅠ==1 && a== 2 &&ᅠa==3) {
console.log("Why hello there!")
}
в
Обратите внимание на странный интервал в если
заявление (что я скопировал из вашего вопроса). Это половина ширины хангыль (что'ы корейский для тех, кто не знаком), который представляет собой космический символ Unicode, который не обрабатывается скрипт ЕСМА как пробел - это означает, что он является допустимым символом для идентификатора. Поэтому есть три совершенно разных переменных, одна с хангыль после, один с ним, прежде чем с просто. Замена пространства С _
для удобства восприятия, один и тот же код будет выглядеть так:
в
var a_ = 1;
var a = 2;
var _a = 3;
if(a_==1 && a== 2 &&_a==3) {
console.log("Why hello there!")
}
в
Проверить проверка на Матиас' переменная валидатор имя. Если этот странный интервал был на самом деле включили в свой вопрос, я уверен, что это'ы намек на такого рода ответ.
Дон'т сделать это. Серьезно.
Редактировать: он пришел к мое внимание, что (хотя и не позволили начать переменная) в нулевой ширины столяр и нулевой ширины не столяр персонажи тоже допускаются в именах переменных - см. обфускация JavaScript с нулевой ширины символов - плюсов и минусов?.
Это будет выглядеть следующим образом:
в
var a= 1;
var a= 2; //one zero-width character
var a= 3; //two zero-width characters (or you can use the other one)
if(a==1&&a==2&&a==3) {
console.log("Why hello there!")
}
в
ЭТО ВОЗМОЖНО!
var i = 0;
with({
get a() {
return ++i;
}
}) {
if (a == 1 && a == 2 && a == 3)
console.log("wohoo");
}
Здесь используется геттер внутри оператора with
, чтобы позволить a
оценить три различных значения.
... это все еще не означает, что это следует использовать в реальном коде...
Что еще хуже, этот трюк также сработает при использовании ===
.
var i = 0;
with({
get a() {
return ++i;
}
}) {
if (a !== a)
console.log("yep, this is printed.");
}
Пример без геттеров или метод valueOf:
в
a = [1,2,3];
a.join = a.shift;
console.log(a == 1 && a == 2 && a == 3);
в
Это работает, потому что ==
вызывает метод toString
, который называет.присоединяйтесь к массивам.
Другое решение, используя символ.toPrimitive, который представляет собой ЕС6 эквивалент метод toString/метод valueOf
:
в
let i = 0;
let a = { [Symbol.toPrimitive]: () => ++i };
console.log(a == 1 && a == 2 && a == 3);
в
Если он попросил, если это возможно (не обязательно), он может спросить "А" возвращает случайное число. Это было бы верно, если бы он генерирует 1, 2, и 3 последовательно.
в
with({
get a() {
return Math.floor(Math.random()*4);
}
}){
for(var i=0;i<1000;i++){
if (a == 1 && a == 2 && a == 3){
console.log("after " + (i+1) + " trials, it becomes true finally!!!");
break;
}
}
}
в
Когда вы можете'т делать без регулярных выражений:
в
var a = {
r: /\d/g,
valueOf: function(){
return this.r.exec(123)[0]
}
}
if (a == 1 && a == 2 && a == 3) {
console.log("!")
}
в
Это работает из-за пользовательских значение
метод, который вызывается, когда объект по сравнению с примитивным (например, количество). Главная хитрость заключается в том, что это.метод valueOf
возвращает новое значение каждый раз, потому что он's запрос метод exec
в регулярное выражение с флагом G, которая вызывает обновление [
свойство lastindex][2] это регулярное выражение каждый раз, когда соответствие найдено. Так что в первый раз это.Р.свойство lastindex == 0
, это совпадает с 1
и обновления свойство lastindex
: в этом.Р.свойство lastindex == 1
, так что в следующий раз регулярное выражение будет соответствовать 2
и так далее.
Это возможно в случае переменные a
используется, скажем 2 рабочих веб-процессов с помощью SharedArrayBuffer а также некоторых основных сценария. Вероятность низкая, но возможно, что, когда код компилируется в машинный код, веб-работников, обновление переменной " а " в условиях а==1
, а==2
и A==3
удовлетворены.
Это может быть пример гонки в многопоточной среде, предоставляемые веб-работники и SharedArrayBuffer в JavaScript.
Вот основные реализации выше:
main.js
// Main Thread
const worker = new Worker('worker.js')
const modifiers = [new Worker('modifier.js'), new Worker('modifier.js')] // Let's use 2 workers
const sab = new SharedArrayBuffer(1)
modifiers.forEach(m => m.postMessage(sab))
worker.postMessage(sab)
worker.js
let array
Object.defineProperty(self, 'a', {
get() {
return array[0]
}
});
addEventListener('message', ({data}) => {
array = new Uint8Array(data)
let count = 0
do {
var res = a == 1 && a == 2 && a == 3
++count
} while(res == false) // just for clarity. !res is fine
console.log(`It happened after ${count} iterations`)
console.log('You should\'ve never seen this')
})
modifier.js
addEventListener('message' , ({data}) => {
setInterval( () => {
new Uint8Array(data)[0] = Math.floor(Math.random()*3) + 1
})
})
На моем MacBook воздуха, это происходит примерно через 10 млрд итераций с первой попытки:
Вторая попытка:
Как я уже сказал, шансы будут низкие, но, учитывая достаточно времени, это'Лл нажмите состояние.
Совет: если это занимает слишком много времени в системе. Попробуйте только а == 1 && в == 2
и измените математика.случайный()*3 " в " Математика.случайный()*2
. Добавляя все больше и больше список выпадает шанс попадания.
Этого можно добиться с помощью следующих действий в глобальной области видимости. Для nodejs
используйте global
вместо window
в приведенном ниже коде.
var val = 0;
Object.defineProperty(window, 'a', {
get: function() {
return ++val;
}
});
if (a == 1 && a == 2 && a == 3) {
console.log('yay');
}
Этот ответ злоупотребляет неявными переменными, предоставляемыми глобальной областью видимости в контексте выполнения, определяя геттер для получения переменной.
Это также возможно, используя ряд самостоятельных перезаписи геттеров:
(Это похоже на опубликовано Anonymous'ы решение, но не't, требуют наличия переменной счетчика.)
в
(() => {
"use strict";
Object.defineProperty(this, "a", {
"get": () => {
Object.defineProperty(this, "a", {
"get": () => {
Object.defineProperty(this, "a", {
"get": () => {
return 3;
}
});
return 2;
},
configurable: true
});
return 1;
},
configurable: true
});
if (a == 1 && a == 2 && a == 3) {
document.body.append("Yes, it’s possible.");
}
})();
в
Кроме того, можно использовать класс для этого и экземпляр для проверки.
в в функция A() { ВАР значение = 0; это.метод valueOf = функция () { возвращаемое значение++; }; }
var a = new A;
if (a == 1 && a == 2 && a == 3) {
console.log('bingo!');
}
в
Редактировать
Используя классы ЕС6 это будет выглядеть так
в
class A {
constructor() {
this.value = 0;
this.valueOf();
}
valueOf() {
return this.value++;
};
}
let a = new A;
if (a == 1 && a == 2 && a == 3) {
console.log('bingo!');
}
в
Я не'т см. Этот ответ уже выложили, поэтому я'буду бросать его в смеси тоже. Это похоже на Джефф'ы ответ с половиной ширины хангыль пространства.
в
var a = 1;
var a = 2;
var а = 3;
if(a == 1 && a == 2 && а == 3) {
console.log("Why hello there!")
}
в
Вы можете заметить незначительные расхождения со второй, но первая и третья идентичны невооруженным глазом. Все 3 являются отдельные символы:
"а" - латинские строчные в
a
- полная ширина латинские строчные в
а
- прописные кириллицей в
Общий термин для этого есть "homoglyphs" в: разных символов Unicode, которые выглядят одинаково. Как правило, трудно получить три, что совершенно неразличимы, но в некоторых случаях вам может повезти. А, Α, А, и Ꭺ будет работать лучше (по-латыни-а греческий Alpha, кириллица-а, и Чероки-а соответственно; к сожалению, греческий и Чероки строчные буквы слишком отличается от латинского а
: α
,ꭺ
, и поэтому не'т помочь приведенного выше фрагмента).
Там'ы целый класс Homoglyph атак там, как правило, в поддельных доменных имен (напр. wikipedia.org
(кириллица) против wikipedia.org
(лат.)), но она может появиться в код, а также, как правило, называют как закулисные (как уже упоминалось в комментарии, [коварный] вопросы по теме на PPCG, но раньше был типа вызов, где такие вещи будут появляться). Я этот сайт, чтобы найти homoglyphs использовать для этого ответа.
в
if=()=>!0;
var a = 9;
if(a==1 && a== 2 && a==3)
{
document.write("<h1>Yes, it is possible!😎</h1>")
}
в
Приведенный выше код-короткая версия (Спасибо @Forivin за его внимание, в комментариях) и следующий код является оригинальным:
в
var a = 9;
if(a==1 && a== 2 && a==3)
{
//console.log("Yes, it is possible!😎")
document.write("<h1>Yes, it is possible!😎</h1>")
}
//--------------------------------------------
function if(){return true;}
в
если вы просто видите верхней части моего кода и его выполнения вам сказать, ничего себе, как?
поэтому я думаю, что это достаточно, чтобы сказать Да, возможно для кого-то что сказал У вас: нет ничего невозможного
трюк: я использовал скрытый символ после
Если
, чтобы сделать функцию, что ее название похоже на "если". В JavaScript мы не можем переопределить ключевые слова, поэтому я вынужден использовать этот способ. Это фейк "Если", но это работает для вас в таком случае!
Также я написал в C# версии (при увеличении стоимости имущества друго):
static int _a;
public static int a => ++_a;
public static void Main()
{
if(a==1 && a==2 && a==3)
{
Console.WriteLine("Yes, it is possible!😎");
}
}
В JavaScript нет [чисел], 1, но только числа, которые реализованы в виде двойной точности с плавающей запятой.
Это означает, что если количество " а " достаточно большой, его можно считать равным трех последовательных целых чисел:
в
a = 100000000000000000
if (a == a+1 && a == a+2 && a == a+3){
console.log("Precision loss!");
}
в
Правда, это'ы не совсем то, что интервьюер спросил (Это вовсе'т работать с а=0
), но это вовсе'т включать любые трюк с скрытых функций и перегрузка операторов.
Для справки, есть А==1 && в==2 && в==3
решения на Ruby и Python. С небольшой модификацией, он's также возможно в Java.
С таможней ==
:
class A
def ==(o)
true
end
end
a = A.new
if a == 1 && a == 2 && a == 3
puts "Don't do this!"
end
Или растущая "а":
def a
@a ||= 0
@a += 1
end
if a == 1 && a == 2 && a == 3
puts "Don't do this!"
end
class A:
def __eq__(self, who_cares):
return True
a = A()
if a == 1 and a == 2 and a == 3:
print("Don't do that!")
Это'можно изменить в Java целое число
кэш:
package stackoverflow;
import java.lang.reflect.Field;
public class IntegerMess
{
public static void main(String[] args) throws Exception {
Field valueField = Integer.class.getDeclaredField("value");
valueField.setAccessible(true);
valueField.setInt(1, valueField.getInt(42));
valueField.setInt(2, valueField.getInt(42));
valueField.setInt(3, valueField.getInt(42));
valueField.setAccessible(false);
Integer a = 42;
if (a.equals(1) && a.equals(2) && a.equals(3)) {
System.out.println("Bad idea.");
}
}
}
Это перевернутая версия @Джефф'ы ответ* где скрытый характер (у+115F, у+1160 или U+3164) используется для создания переменных, которые выглядят как 1
, 2
и 3
.
в
var a = 1;
var ᅠ1 = a;
var ᅠ2 = a;
var ᅠ3 = a;
console.log( a ==ᅠ1 && a ==ᅠ2 && a ==ᅠ3 );
в
* Что ответ может быть упрощена с помощью нулевой ширины не столяр (от U+200С) и нулевой ширины столярный (у+ткань 200D). Оба эти символы разрешены внутри идентификаторов, но не в начале:
в
var a = 1;
var a = 2;
var a = 3;
console.log(a == 1 && a == 2 && a == 3);
/****
var a = 1;
var a\u200c = 2;
var a\u200d = 3;
console.log(a == 1 && a\u200c == 2 && a\u200d == 3);
****/
в
Другие приемы можно, используя ту же идею, например, с помощью Unicode вариации селекторы для создания переменных, которые выглядят точно так (`a︀ = 1; a︁ = 2; a︀ == 1 && a︁ == 2; // значение true).
Правило номер один интервью; никогда не говори невозможно.
Не надо скрытый характер плутовства.
в
window.__defineGetter__( 'a', function(){
if( typeof i !== 'number' ){
// define i in the global namespace so that it's not lost after this function runs
i = 0;
}
return ++i;
});
if( a == 1 && a == 2 && a == 3 ){
alert( 'Oh dear, what have we done?' );
}
в
Хотя если честно, есть ли способ для того, чтобы оценить значение true или нет (и как уже показано, есть несколько способов), ответа я'd быть ищу, говорю как тот, кто провел сотни интервью, будет что-то вдоль линий:
и"Ну, может быть, да под каким-то странное стечение обстоятельств, что ты'т очевидным для меня... но если бы я столкнулся с этим в реальном коде я бы тогда использовать общие методики отладки, чтобы выяснить, как и почему он делал то, что он делает, и затем немедленно выполнить рефакторинг кода, чтобы избежать этой ситуации... но главное: я совершенно нигде не пишут, что код в первую очередь потому, что само определение запутанный код, и я стараюсь никогда не писать запутанный код и".
Я думаю, что некоторые интервьюеры будут обижаться на то, что явно означало быть очень каверзный вопрос окликнула, но я не'т ум разработчикам, которые имеют свое мнение, особенно, когда они могут подтвердить это, а логическое мышление и сможет занять мой вопрос в осмысленное высказывание о себе.
Если вы когда-нибудь сделать такое интервью (или заметить некоторые столь же непредсказуемому поведению кода) подумайте, какие вещи могут вызвать поведение, которое кажется невозможным на первый взгляд:
Кодирование: в этом случае переменной вы смотрите не тот что вы думаете. Это может произойти, если вы намеренно возиться с Unicode, используя homoglyphs или пробелы, чтобы имя переменной похожим на другого, но кодирование вопросы могут также быть введены случайно, например, при копировании и усилитель; вставить код из интернета, который содержит неожиданные кодовых точек Unicode (например, система управления контентом вообще какая-то "Авто-форматирование" и такие, как замена Флорида
с Unicode 'ЛАТИНСКАЯ СТРОЧНАЯ ЛИГАТУРА ФЛ' (У+FB02)).
Гонки: а гонки может произойти, т. е. ситуации, когда код не выполняется в последовательности, ожидаемый разработчиком. Гонки часто бываю в многопоточном коде, но несколько потоков не является обязательным требованием для гонки условия, которые должны быть возможно – asynchronicity достаточно (и Дон'т запутаться, асинхронного вовсе не означает, нескольких потоков используются под капотом).
Внимание, что JavaScript-это тоже не свободна от условий гонки только потому, что он является однопоточным. Смотрите здесь для простой однопоточный – но асинхронность – пример. В рамках одной инструкции, однако состояние гонки будет довольно трудно попасть в JavaScript.
JavaScript вместе с веб-работников немного отличается, как вы можете иметь несколько потоков. @mehulmpt показала нам великий доказательство концепции, используя веб-работников.
Такого рода вопросы могут появиться во многих языках программирования, а не только JavaScript, так что мы не'т видим один из классических JavaScript в WTFs здесь<суп>1</хлебать>.
Конечно, вопрос интервью и здесь все образцы выглядят очень надуманными. Но они являются хорошим напоминанием о том, что:
<суб><суп>1</SUP-серфинг> например, вы можете найти пример в совершенно разных языка программирования (С#), проявляя побочный эффект (очевидный) здесь.</суб>
Здесь'с другой вариации, используя массив, чтобы палить, что значения, которые вы хотите.
в
const a = {
n: [3,2,1],
toString: function () {
return a.n.pop();
}
}
if(a == 1 && a == 2 && a == 3) {
console.log('Yes');
}
в
Ладно, еще один хак с генераторами:
в
const value = function* () {
let i = 0;
while(true) yield ++i;
}();
Object.defineProperty(this, 'a', {
get() {
return value.next().value;
}
});
if (a === 1 && a === 2 && a === 3) {
console.log('yo!');
}
в
Используя Прокси:
var a = new Proxy({ i: 0 }, {
get: (target, name) => name === Symbol.toPrimitive ? () => ++target.i : target[name],
});
console.log(a == 1 && a == 2 && a == 3);
Прокси в основном притворяются целевого объекта (первый параметр), но перехватить операций целевого объекта (в данном случае на "Вы" и работы) так что есть возможность сделать что-то другое, чем по умолчанию поведение объекта. В этом случае на "Вы" в действии называется на а
когда ==
принуждает его тип для того, чтобы сравнить его с каждым номером. Это происходит:
{ Я: 0 }
, где я
- это свойство нашего счетчикаа ==
сравнения а
's тип приводится к примитивное значениеэто[символ.функция toPrimitive]
с помощью "и сделать обработчик"и++цель.я
. Если собственность будет восстановлена, мы просто отступаем, чтобы возвратить значение свойства по умолчанию, `цель[имя]Так:
var a = ...; // a.valueOf == target.i == 0
a == 1 && // a == ++target.i == 1
a == 2 && // a == ++target.i == 2
a == 3 // a == ++target.i == 3
Как и в большинстве других ответов, это работает только с рыхлым проверить равенства (==
), потому что строгие проверки равенства (===
) не делать приведение типов, что прокси может перехватить.