Примечание модератора: Пожалуйста, не поддавайтесь желанию изменить код или удалить это уведомление. Структура пробелов может быть частью вопроса и, следовательно, не должна вмешиваться излишне. Если вы находитесь в лагере «пустое пространство незначительно», вы сможете принять код как есть.
Это когда-либо возможно, что (a== 1 && a ==2 && a==3)
может оценитьtrue
в JavaScript?
Это вопрос интервью, заданный крупной технологической компанией. Это случилось две недели назад, но я все еще пытаюсь найти ответ. Я знаю, что мы никогда не пишем такой код в нашей повседневной работе, но мне любопытно.
javascript
ecmascript-6
Димпу Аравинд Будда
источник
источник
==
когда вы имеете в виду===
, имейте стандарт кодирования, который запрещает имена переменных, отличных от ASCII, и используйте процесс линтинга, который обеспечивает соблюдение двух предыдущих моралей.Ответы:
Если вы воспользуетесь том , как
==
работы , вы можете просто создать объект с пользовательскойtoString
(илиvalueOf
функции) , которая изменяет то , что она возвращает каждый раз , когда он используется так , что она удовлетворяет всем трем условиям.Причина, по которой это работает, заключается в использовании оператора свободного равенства. При использовании свободного равенства, если один из операндов имеет другой тип, чем другой, механизм будет пытаться преобразовать один в другой. В случае объекта слева и числа справа он будет пытаться преобразовать объект в число, сначала вызвав
valueOf
его, если он вызывается, и в случае неудачи он вызоветtoString
. Я использовалtoString
в этом случае просто потому, что это то, что пришло на ум,valueOf
будет больше смысла. Если бы я вместо этого возвратил строку изtoString
, то движок попытался бы преобразовать строку в число, что дало бы тот же конечный результат, хотя и с немного более длинным путем.источник
valueOf()
операцию?valueOf
будет немного лучше.i
, не беспокоит движок. ;)Я не мог удержаться - другие ответы, несомненно, верны, но вы действительно не можете пройти мимо следующего кода:
Обратите внимание на странный интервал в
if
утверждении (которое я скопировал из вашего вопроса). Это хангул половинной ширины (это корейский для тех, кто не знаком), который является символом пробела Unicode, который не интерпретируется сценарием ECMA как символ пробела - это означает, что это допустимый символ для идентификатора. Поэтому есть три совершенно разные переменные, одна с хангул после a, одна с ним до, а последняя с просто a. Заменив пространство_
на удобочитаемость, тот же код будет выглядеть так:Проверьте валидацию на валидаторе имени переменной Матиаса . Если этот странный интервал действительно был включен в их вопрос, я уверен, что это подсказка для такого рода ответа.
Не делай этого. Шутки в сторону.
Edit: Он пришел к моему вниманию , что (хотя и не разрешаются начинать переменный) нулевая ширину столяра и нулевой ширина не-столярные символы также разрешены в именах переменных - см запутываний JavaScript с нулевой шириной символами - плюсами и минусами ? ,
Это будет выглядеть следующим образом:
источник
var ᅠ2 = 3
Была использована переменная ; так что есть три переменныеaᅠᅠ= 1, ᅠ2 = 3, a = 3
(a␣ = 1, ␣2 = 3, a = 3
так, чтобы(a␣==1 && a==␣2 && a==3)
) ...ЭТО ВОЗМОЖНО!
При этом используется метод получения внутри
with
оператора, чтобы позволитьa
оценить три различных значения.... это еще не значит, что это должно быть использовано в реальном коде ...
Еще хуже, этот трюк также будет работать с использованием
===
.источник
with
».with
это не разрешено.with
чтобы это могло произойти==
. И===
мешает принятому ответу==
но я не виделwith
с тех пор ... ну, на самом деле никогда не выходил за рамки документации JS, где написано "пожалуйста, не используйте это". В любом случае, хорошее решение.Пример без геттеров или значения:
Это работает, потому что
==
вызываетtoString
какие вызовы.join
массивы.Другое решение, использующее
Symbol.toPrimitive
ES6-эквивалентtoString/valueOf
:источник
without valueOf
ну ... это более косвенно, но в основном то же самое.toString
или ,valueOf
но это один полностью поймал меня из охраны. Очень умный, и я не знал, что он звонил.join
изнутри, но это имеет смысл.Если его спросить, возможно ли это (не ДОЛЖНО), он может попросить «а» вернуть случайное число. Было бы верно, если бы он генерировал 1, 2 и 3 последовательно.
источник
Когда вы ничего не можете сделать без регулярных выражений:
Это работает из-за пользовательского
valueOf
метода, который вызывается, когда Object сравнивается с примитивом (таким как Number). Основной трюк заключается в том, чтоa.valueOf
каждый раз возвращается новое значение, потому что он вызываетexec
регулярное выражение сg
флагом, что вызывает обновлениеlastIndex
этого регулярного выражения каждый раз, когда найдено совпадение. Так что в первый разthis.r.lastIndex == 0
, это соответствует1
и обновляетlastIndex
:,this.r.lastIndex == 1
так что в следующий раз регулярное выражение будет соответствовать2
и так далее.источник
exec
которому он соответствует, повторный вызов начнет поиск по этому индексу. МДН не очень понятно.this.r
объект регулярного выражения запоминает состояние / индекс. Спасибо!exec
хотя, а не целое число для преобразования в строку .Это может быть достигнуто с помощью следующего в глобальной области видимости. Для
nodejs
использования,global
а неwindow
в коде ниже.Этот ответ использует неявные переменные, предоставляемые глобальной областью действия в контексте выполнения, определяя метод получения для получения переменной.
источник
a
что это свойство,this
которым оно не является. Если быa
была локальная переменная (как это выглядит), то это не сработало бы.a == 1
подразумевает,a
что где-то есть переменная, а не свойствоthis
. Хотя есть странное место, такое как глобальные переменные, где оба могут быть истинными, обычно объявление переменной с помощьюvar a
илиlet a
означает, что нетthis
, позволяет вам обращатьсяa
как к свойству, как предполагает код. Итак, ваш код, очевидно, предполагает некоторую странную глобальную переменную. Например, ваш код не работает в node.js и не работает в строгом режиме внутри функции. Вы должны указать точные обстоятельства, где это работает, и, вероятно, объяснить, почему это работает. В противном случае это вводит в заблуждение.a
это не локальная переменная, а определяется в глобальной области с возрастающим геттером.Это возможно в случае, когда к переменной
a
обращаются, скажем, 2 веб-работника через SharedArrayBuffer, а также некоторый основной скрипт. Возможность невелика, но вполне возможно , что , когда код компилируется в машинный код, веб - рабочие обновить переменнуюa
как раз вовремя , так что условияa==1
,a==2
иa==3
удовлетворены.Это может быть примером состояния гонки в многопоточной среде, предоставляемой веб-работниками и SharedArrayBuffer в JavaScript.
Вот основная реализация выше:
main.js
worker.js
modifier.js
На моем MacBook Air это происходит после 10 миллиардов итераций с первой попытки:
Вторая попытка:
Как я уже сказал, шансы будут низкими, но если уделить достаточно времени, это приведет к ухудшению состояния.
Совет: если это занимает слишком много времени в вашей системе. Попробуйте только
a == 1 && a == 2
и изменитеMath.random()*3
наMath.random()*2
. Добавление все больше и больше в список снижает вероятность попадания.источник
Это также возможно с использованием ряда перезаписывающих геттеров:
(Это похоже на решение jontro, но не требует переменной счетчика.)
источник
===
, а не только==
.this
том, чтобы быть глобальным объектом внутри тела функции стрелки.(a == 3 && a == 2 && a == 1)
?В качестве альтернативы вы можете использовать класс для него и экземпляр для проверки.
РЕДАКТИРОВАТЬ
С использованием классов ES6 это будет выглядеть так
источник
function A() {value = 0;
в начале?valueOf
переопределяется,this method is usually called automatically by JavaScript behind the scenes, and not explicitly in code
поэтому, когда мы сравниваем значение, оно фактически увеличивает ..Я не вижу этот ответ уже опубликованным, поэтому я тоже добавлю этот ответ. Это похоже на ответ Джеффа с полушириной пространства Хангула.
Вы можете заметить небольшое расхождение со вторым, но первый и третий идентичны невооруженным глазом. Все 3 разных персонажа:
a
- латинская строчная Aa
- полная латинская строчная Aа
- кириллическая строчная AОбщий термин для этого - «гомоглифы»: разные символы юникода, которые выглядят одинаково. Обычно трудно получить три , которые совершенно неразличимы, но в некоторых случаях вам может повезти. A, Α, А и Ꭺ будут работать лучше (латиница-A, греческая альфа , кириллица-A , и Cherokee-A соответственно, к сожалению, греческие и чероки строчные буквы слишком отличаются от латинского
a
:α
,ꭺ
и так Безразлично помогите с приведенным фрагментом).Существует целый класс атак на гомоглифы, чаще всего в поддельных доменных именах (например,
wikipediа.org
(кириллица) противwikipedia.org
(латиница)), но он также может отображаться в коде; обычно упоминается как закулисный (как упомянуто в комментарии, [закулисные] вопросы теперь не по теме PPCG , но раньше это был тип проблемы, когда такие вещи появлялись ). я использовал этот сайт, чтобы найти гомоглифы, используемые для этого ответа.источник
a
:a︀
a︁
a︂
. Больше не нужно беспокоиться о расхождениях.Да, это возможно! 😎
»JavaScript
Приведенный выше код является короткой версией (спасибо @Forivin за примечание в комментариях), а следующий код является оригинальным:
» C #
Также я написал C # версию ( с техникой увеличения значения свойства ):
Live Demo
источник
if=()=>!0
document.write
? Это верный способ не получить работу независимо от остальной части ответа.console.log
но изменил его на document.write. Действительно, я всегда используюconsole.log
в своих кодах, но здесь я просто хочу показать текст пользователям в поле фрагмента кода StackOverflow. Поэтому я хотел показать свое сообщение более красивым, чем сообщение, сгенерированноеconsole.log
. НажмитеRun Code Snippet
кнопку моего ответа и других ответов. Фрагмент кода SO позволил мне использовать html, JS и CSS, а затем я захотел использовать его в своем ответе и сделать его красивым. Я думаю, что это не имеет никакого отрицательного побочного эффекта и не сделало мой ответ большим или законченным.JavaScript
a == a +1
В JavaScript нет целых чисел, а только
Number
s, которые реализованы как числа с плавающей запятой двойной точности.Это означает, что если число
a
достаточно велико, его можно считать равным трем последовательным целым числам:Правда, это не совсем то, что спросил интервьюер (это не работает с
a=0
), но это не связано с уловкой со скрытыми функциями или перегрузкой операторов.Другие языки
Для справки, есть
a==1 && a==2 && a==3
решения на Ruby и Python. С небольшой модификацией это также возможно в Java.Рубин
С кастомом
==
:Или увеличение
a
:питон
Ява
Можно изменить
Integer
кэш Java :источник
Integer a = 42
(или не работает)? Как я понимаю, автобокс,Integer a = 42; a == 1 && a == 2 && a == 3
должен боксировать все ints. Или это распаковать для сравнения?Integer == int
кажется, приводит к распаковке. Но используяInteger#equals(int)
силы автобокса, так оно и работает. Спасибо за комментарий!Numbers
в JS, которые в основном похожи наdouble
s. Они могут выглядеть как целые числа, и вы можете использовать их как целые числа, но они все еще не являются целыми числами. Я не думаю, чтоn == n + 1
когда-либо может быть правдой для целых чисел в Java / Python / C / Ruby / ...Это перевернутая версия ответа @ Jeff *, где скрытый символ (U + 115F, U + 1160 или U + 3164) используется для создания переменных, которые выглядят как
1
,2
и3
.* Этот ответ можно упростить, если использовать несоединение с нулевой шириной (U + 200C) и соединение с нулевой шириной (U + 200D). Оба эти символа допускаются внутри идентификаторов, но не в начале:
Другие приемы возможны при использовании той же идеи, например, с помощью селекторов вариаций Unicode для создания переменных, которые выглядят одинаково (
a︀ = 1; a︁ = 2; a︀ == 1 && a︁ == 2; // true
).источник
Правило номер один из интервью; никогда не говори невозможно.
Нет необходимости для скрытого обмана персонажа.
источник
__defineGetter__
на самом деле не является частью языка JS, просто уродливая версияdefineProperty
.typeof
это не функция, и это необъявленноеi
просто ужасно. Все еще, кажется, стоит 40 голосов: /__defineGetter__
не рекомендуется для developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… но он явно выполняется в моем FireFox v 57.0.4, поэтому я решил показать это вместоdefineProperty()
потому что унаследованный код реален и не может быть проигнорирован. Независимо от уродства, декларация,i
как я это сделал, является хорошо известным / задокументированным поведением. Может быть, я был просто в настроении PCG ¯ \ _ (ツ) _ / ¯Хотя, если честно, есть ли у него способ оценить истинность или нет (и, как показали другие, есть несколько способов), ответ, который я искал бы, говоря как человек, который провел сотни интервью, был бы что-то вроде:
«Ну, может быть, да при каких-то странных обстоятельствах, которые не сразу очевидны для меня ... но если бы я столкнулся с этим в реальном коде, то я бы использовал общие методы отладки, чтобы выяснить, как и почему он делал то, что делал и затем немедленно реорганизовать код, чтобы избежать такой ситуации ... но что более важно: я бы НИКОГДА не писал этот код, во-первых, потому что это само определение сложного кода, и я стараюсь никогда не писать сложный код ".
Я полагаю, что некоторые интервьюеры обидятся за то, что этот вопрос, очевидно, должен быть очень сложным, но я не возражаю против разработчиков, у которых есть мнение, особенно когда они могут подкрепить его аргументированной мыслью и могут согласовать мой вопрос с значимое утверждение о себе.
источник
Если у вас когда-нибудь возникнет такой вопрос на собеседовании (или вы заметите какое-то столь же неожиданное поведение в вашем коде), подумайте о том, какие вещи могут вызвать поведение, которое на первый взгляд кажется невозможным:
Кодировка : в этом случае переменная, на которую вы смотрите, не та, о которой вы думаете. Это может произойти, если вы намеренно возитесь с Юникодом, используя гомоглифы или пробелы, чтобы имя переменной выглядело как другая, но проблемы с кодированием также могут возникать случайно, например, при копировании и вставке кода из Интернета, который содержит неожиданный код Unicode точки (например, потому что система управления контентом сделала некоторое «автоматическое форматирование», например, заменив
fl
Unicode «LATIN SMALL LIGATURE FL» (U + FB02)).Условия гонки : A гонки состояние может возникнуть, например , ситуация , когда код не выполняется в последовательности ожидаемого разработчиком. Условия гонки часто бывают в многопоточном коде, но наличие нескольких потоков не является обязательным условием, чтобы условия гонки были возможны - асинхронность достаточна (и не путайте, асинхронность не означает, что несколько потоков используются под капотом ).
Обратите внимание, что поэтому JavaScript также не свободен от условий гонки только потому, что он однопоточный. Смотрите здесь для простого однопоточного - но асинхронного - примера. Однако в контексте одного утверждения условие гонки будет довольно сложно выполнить в JavaScript.
JavaScript с веб-работниками немного отличается, так как вы можете иметь несколько потоков. @mehulmpt показал нам отличное подтверждение концепции с использованием веб-работников .
Побочные эффекты : побочный эффект операции сравнения на равенство (который не должен быть таким очевидным, как в приведенных здесь примерах, часто побочные эффекты очень тонкие).
Такого рода вопросы может появляться во многих языках программирования, а не только JavaScript, поэтому мы не видим один из классического JavaScript WTFs здесь 1 .
Конечно, вопрос интервью и образцы здесь выглядят очень надуманными. Но они являются хорошим напоминанием о том, что:
1 Например, вы можете найти пример в совершенно другом языке программирования (C #) экспонирование побочного эффекта (очевидный) здесь .
источник
Вот еще один вариант, использующий массив для выталкивания любых значений, которые вы хотите.
источник
Хорошо, еще один взлом с генераторами:
источник
this
того, чтобы быть оконным объектом)Использование прокси :
Прокси в основном претендуют на то, чтобы быть целевым объектом (первый параметр), но перехватывают операции на целевом объекте (в данном случае операция «get property»), так что есть возможность сделать что-то отличное от поведения объекта по умолчанию. В этом случае действие «get property» вызывается
a
при приведении==
его типа для сравнения его с каждым числом. Это случилось:{ i: 0 }
, гдеi
свойство является нашим счетчикомa
a ==
сравненияa
тип приводится к примитивному значению.a[Symbol.toPrimitive]()
внутреннему вызовуa[Symbol.toPrimitive]
функции, используя «обработчик get»Symbol.toPrimitive
, в этом случае он увеличивает и возвращает счетчик от целевого объекта:++target.i
. Если извлекается другое свойство, мы просто возвращаемся к возвращению значения свойства по умолчанию,target[name]
Так:
Как и с большинством других ответов, это работает только с произвольной проверкой равенства (
==
), потому что строгие проверки равенства (===
) не приводят к принуждению типов, которое прокси-сервер может перехватить.источник
Symbol.toPrimitive
точно так же можно определить и объект.На самом деле ответ на первую часть вопроса - «Да» на каждом языке программирования. Например, это в случае C / C ++:
источник
&&
для логических «и».То же, но другое, но все же (можно «проверить» несколько раз):
Моя идея началась с того, как работает уравнение типа объекта Number.
источник
Ответ ECMAScript 6, в котором используются символы:
Благодаря
==
использованию, JavaScript должен принуждатьa
в нечто близкое к второй операнд (1
,2
,3
в данном случае). Но прежде чем JavaScript попытается определить принуждение самостоятельно, он пытается вызватьSymbol.toPrimitive
. Если вы предоставитеSymbol.toPrimitive
JavaScript, будет использовать значение, которое возвращает ваша функция. Если нет, JavaScript будет вызыватьvalueOf
.источник
Я думаю, что это минимальный код для его реализации:
Создание фиктивного объекта с пользовательским элементом,
valueOf
который увеличивает глобальную переменнуюi
при каждом вызове. 23 персонажа!источник
Этот использует defineProperty с хорошим побочным эффектом, вызывающим глобальную переменную!
источник
a
:get: (a => () => ++a)(0),
глобально не нужно.Переопределив
valueOf
в объявлении класса, это можно сделать:Что происходит, это
valueOf
вызывается в каждом операторе сравнения. На первомa
будет равен1
, на второмa
будет равен2
, и так далее, и так далее, потому что каждый раз, когдаvalueOf
вызывается, значениеa
увеличивается.Поэтому console.log будет запускаться и выводиться (в любом случае в моем терминале)
Thing: { value: 4}
, указывая, что условие было истинным.источник