Nota do moderador: resista ao desejo de editar o código ou remover este aviso. O padrão de espaço em branco pode fazer parte da pergunta e, portanto, não deve ser adulterado desnecessariamente. Se você estiver no campo "espaço em branco é insignificante", poderá aceitar o código como está.
É possível (a== 1 && a ==2 && a==3)
avaliar true
em JavaScript?
Esta é uma pergunta de entrevista feita por uma grande empresa de tecnologia. Isso aconteceu duas semanas atrás, mas ainda estou tentando encontrar a resposta. Sei que nunca escrevemos esse código em nosso trabalho cotidiano, mas estou curioso.
javascript
ecmascript-6
Dimpu Aravind Buddha
fonte
fonte
==
quando você quer dizer===
, tenha um padrão de codificação que proíba nomes de variáveis não ASCII e tenha um processo de vinculação que imponha as duas morais anteriores.Respostas:
Se você tirar proveito de como
==
funciona , você pode simplesmente criar um objeto com uma função personalizadatoString
(ouvalueOf
) que altera o que ele retorna cada vez que é usado, de modo a satisfazer todas as três condições.A razão pela qual isso funciona é devido ao uso do operador de igualdade frouxa. Ao usar igualdade solta, se um dos operandos for de um tipo diferente do outro, o mecanismo tentará converter um para o outro. No caso de um objeto à esquerda e um número à direita, ele tentará converter o objeto em um número ligando primeiro,
valueOf
se for possível chamar , e, na sua falta, ligarátoString
. Eu useitoString
neste caso simplesmente porque é o que me veio à mente,valueOf
faria mais sentido. Se eu retornasse uma string detoString
, o mecanismo tentaria converter a string em um número, fornecendo o mesmo resultado final, embora com um caminho um pouco mais longo.fonte
valueOf()
operação implícita ?valueOf
é um pouco melhor.i
não incomoda o mecanismo. ;)Não pude resistir - as outras respostas são indubitavelmente verdadeiras, mas você realmente não pode passar pelo seguinte código:
Observe o espaçamento estranho na
if
declaração (que copiei da sua pergunta). É o Hangul de meia largura (que é coreano para quem não conhece) que é um caractere de espaço Unicode que não é interpretado pelo script ECMA como um caractere de espaço - isso significa que é um caractere válido para um identificador. Portanto, existem três variáveis completamente diferentes, uma com o Hangul após a, uma com ele antes e a última com apenas a. Substituindo o espaço_
por legibilidade, o mesmo código ficaria assim:Confira a validação no validador de nome de variável do Mathias . Se esse espaçamento estranho foi realmente incluído na pergunta, tenho certeza de que é uma dica para esse tipo de resposta.
Não faça isso. A sério.
Edit: Chegou ao meu conhecimento que (embora não seja autorizado a iniciar uma variável), o marceneiro de largura zero e zero-width não marcenaria personagens também são permitidos em nomes de variáveis - ver ofuscando JavaScript com de largura zero personagens - prós e contras ? .
Seria o seguinte:
fonte
var ᅠ2 = 3
foi usada; então existem as três variáveisaᅠᅠ= 1, ᅠ2 = 3, a = 3
(a␣ = 1, ␣2 = 3, a = 3
, para que(a␣==1 && a==␣2 && a==3)
) ...É POSSÍVEL!
Isso usa um getter dentro de uma
with
instrução para permitira
avaliar três valores diferentes.... isso ainda não significa que isso deva ser usado em código real ...
Pior ainda, esse truque também funcionará com o uso de
===
.fonte
with
".with
não é permitido.with
que ele possa acontecer==
. E===
impede a resposta aceita==
mas eu não as vejowith
desde ... bem, na verdade nunca fora da documentação do JS, onde diz "por favor, não use isso". Enfim, uma boa solução.Exemplo sem getters ou valueOf:
Isso funciona porque
==
chamatoString
quais chamadas.join
para matrizes.Outra solução, usando o
Symbol.toPrimitive
que é um equivalente ES6 detoString/valueOf
:fonte
without valueOf
, bem ... é mais indireto, mas basicamente a mesma coisa.toString
ouvalueOf
mas essa me pegou completamente desprevenido. Muito esperto e eu não sabia que ele ligava.join
internamente, mas faz total sentido.Se for perguntado se é possível (não DEVE), ele pode pedir a "a" para retornar um número aleatório. Seria verdade se gerar 1, 2 e 3 sequencialmente.
fonte
Quando você não pode fazer nada sem expressões regulares:
Funciona devido ao
valueOf
método personalizado chamado quando Object comparado com o primitivo (como Number). O truque principal é quea.valueOf
retorna um novo valor toda vez porque está chamandoexec
a expressão regular comg
sinalizador, o que causa a atualizaçãolastIndex
dessa expressão regular toda vez que a correspondência é encontrada. Então, pela primeira vezthis.r.lastIndex == 0
, ele corresponde1
e atualizaçõeslastIndex
:this.r.lastIndex == 1
, tão próxima regex tempo irá corresponder2
e assim por diante.fonte
exec
novamente começará a pesquisar nesse índice. MDN não é muito claro.this.r
objeto regex lembra o estado / índice. Obrigado!exec
porém, não um número inteiro a ser stringified.Isso pode ser realizado usando o seguinte no escopo global. Para
nodejs
uso emglobal
vez dewindow
no código abaixo.Esta resposta abusa das variáveis implícitas fornecidas pelo escopo global no contexto de execução, definindo um getter para recuperar a variável.
fonte
a
é uma propriedade dathis
qual não parece ser. Sea
fosse uma variável local (que parece), isso não funcionaria.a == 1
implica quea
é uma variável em algum lugar, não uma propriedade dethis
. Embora exista um lugar excêntrico como globais em que ambos possam ser verdadeiros, geralmente declarar uma variável comvar a
oulet a
significa que não existe nenhumthis
que permita acessara
como uma propriedade que o código assume. Então, seu código aparentemente está assumindo algo estranho de variável global. Por exemplo, seu código não funciona no node.js e não no modo estrito dentro de uma função. Você deve especificar as circunstâncias exatas em que funciona e provavelmente explicar por que funciona. Caso contrário, é enganoso.a
não é uma variável local e é definida no escopo global com um getter crescente.Isso é possível no caso de a variável
a
ser acessada por, digamos, 2 trabalhadores da Web por meio de um SharedArrayBuffer, além de algum script principal. A possibilidade é baixa, mas é possível que, quando o código é compilado para código de máquina, os trabalhadores web atualizar a variávela
apenas no tempo para que as condiçõesa==1
,a==2
ea==3
estão satisfeitos.Este pode ser um exemplo de condição de corrida em ambiente multithread fornecido por trabalhadores da Web e SharedArrayBuffer em JavaScript.
Aqui está a implementação básica acima:
main.js
worker.js
modifier.js
No meu MacBook Air, isso ocorre após cerca de 10 bilhões de iterações na primeira tentativa:
Segunda tentativa:
Como eu disse, as chances serão baixas, mas, com tempo suficiente, ela atingirá a condição.
Dica: Se demorar muito no seu sistema. Tente apenas
a == 1 && a == 2
e mudeMath.random()*3
paraMath.random()*2
. Adicionar mais e mais à lista diminui a chance de acertar.fonte
Isso também é possível usando uma série de getters de sobregravação automática:
(Isso é semelhante à solução de jontro, mas não requer uma variável de contador.)
fonte
===
, não apenas==
.this
ser o objeto global dentro do corpo da função de seta.(a == 3 && a == 2 && a == 1)
?Como alternativa, você pode usar uma classe para isso e uma instância para a verificação.
EDITAR
Usando classes ES6, ficaria assim
fonte
function A() {value = 0;
no começo?valueOf
está sendo substituído,this method is usually called automatically by JavaScript behind the scenes, and not explicitly in code
por isso, quando se compara o valor que ele realmente incrementa a ..Eu não vejo essa resposta já postada, então eu vou jogar essa também. Isso é semelhante à resposta de Jeff com o espaço Hangul de meia largura.
Você pode notar uma ligeira discrepância com o segundo, mas o primeiro e o terceiro são idênticos a olho nu. Todos os três são caracteres distintos:
a
- Letra minúscula latina Aa
- Letra minúscula latina A completaа
- Letras minúsculas cirílicas AO termo genérico para isso é "homoglifos": caracteres unicode diferentes que têm a mesma aparência. Normalmente é difícil conseguir três totalmente indistinguíveis, mas em alguns casos você pode ter sorte. A, Α, А, e Ꭺ iria funcionar melhor (Latin-A, alfa grego , cirílico-A , e Cherokee-A , respectivamente; infelizmente, o grego e Cherokee letras minúsculas são muito diferentes do latim
a
:α
,ꭺ
e assim doesn ajuda com o trecho acima).Existe toda uma classe de ataques de homoglyph por aí, mais comumente em nomes de domínio falsos (por exemplo,
wikipediа.org
(cirílico) vswikipedia.org
(latino)), mas também pode aparecer no código; normalmente referidos como sendo dissimulados (como mencionado em um comentário, perguntas [dissimuladas] agora estão fora de tópico no PPCG , mas costumavam ser um tipo de desafio em que esses tipos de coisas apareciam). Usei este site para encontrar os homoglifos usados para esta resposta.fonte
a
:a︀
a︁
a︂
. Não precisa mais se preocupar com discrepâncias.Sim, é possível! 😎
»JavaScript
O código acima é uma versão curta (obrigado a @Forivin por sua observação nos comentários) e o código a seguir é original:
» C #
Também escrevi uma versão em C # ( com o aumento da propriedade value technic ):
Demonstração ao vivo
fonte
if=()=>!0
document.write
? Essa é uma maneira infalível de não ser contratado, independentemente do restante da resposta.console.log
mas mudei para document.write. Realmente sempre usoconsole.log
nos meus códigos, mas aqui só quero mostrar um texto aos usuários na caixa de trechos de código StackOverflow. Então, eu queria mostrar minha mensagem mais bonita do que a mensagem gerada porconsole.log
. Clique noRun Code Snippet
botão na minha resposta e em outras respostas. O SO Code Snippet me permitiu usar html e JS e CSS, então eu queria usá-lo na minha resposta e torná-lo agradável. Eu acho que não tem nenhum efeito colateral negativo e não fez minha resposta grande ou completa.Javascript
a == a +1
Em JavaScript, não há números inteiros, mas apenas
Number
s, que são implementados como números de ponto flutuante de precisão dupla.Isso significa que, se um número
a
for grande o suficiente, ele poderá ser considerado igual a três números inteiros consecutivos:É verdade que não é exatamente o que o entrevistador pediu (não funciona com
a=0
), mas não envolve nenhum truque com funções ocultas ou sobrecarga do operador.Outras línguas
Para referência, existem
a==1 && a==2 && a==3
soluções em Ruby e Python. Com uma pequena modificação, também é possível em Java.Rubi
Com um costume
==
:Ou um aumento
a
:Pitão
Java
É possível modificar o
Integer
cache Java :fonte
Integer a = 42
(ou funciona)? Pelo que entendi, aInteger a = 42; a == 1 && a == 2 && a == 3
caixa automática deve conter todas as entradas. Ou isso desmarca um para as comparações?Integer == int
parece resultar em unboxing. Mas usarInteger#equals(int)
forças para autoboxing, para que funcione. Obrigado pelo comentário!Numbers
no JS, que são basicamente comodouble
s. Eles podem parecer números inteiros e você pode usá-los como números inteiros, mas ainda não são números inteiros. Eu não acho quen == n + 1
nunca pode ser verdade para inteiros em Java / Python / C / Ruby / ...Esta é uma versão invertida do @ de Jeff resposta * onde um personagem oculto (U + 115F, U + 1160 ou U + 3164) é usado para criar variáveis que olhar como
1
,2
e3
.* Essa resposta pode ser simplificada usando o marceneiro de largura zero (U + 200C) e o marceneiro de largura zero (U + 200D). Ambos os caracteres são permitidos dentro de identificadores, mas não no começo:
Outros truques são possíveis usando a mesma idéia, por exemplo, usando seletores de variação Unicode para criar variáveis que se parecem exatamente (
a︀ = 1; a︁ = 2; a︀ == 1 && a︁ == 2; // true
).fonte
Regra número um das entrevistas; nunca diga impossível.
Não há necessidade de truques de caracteres ocultos.
fonte
__defineGetter__
na verdade não faz parte da linguagem js, apenas uma versão feia dodefineProperty
.typeof
não é uma função e isso não declaradoi
é simplesmente horrível. Ainda parece valer 40 votos positivos: /__defineGetter__
foi preterido por developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…, mas ele é executado claramente no meu FireFox v 57.0.4, então optei por mostrar isso em vez dedefineProperty()
porque o código legado é real e não pode ser ignorado. Independentemente da feiúra, declarari
da maneira que eu fiz é um comportamento bem conhecido / documentado. Talvez eu era apenas em um clima PCG ¯ \ _ (ツ) _ / ¯Honestamente, se existe uma maneira de avaliar se é verdade ou não (e, como outros demonstraram, existem várias maneiras), a resposta que eu procuraria, falando como alguém que conduziu centenas de entrevistas, seria algo ao longo das linhas de:
"Bem, talvez sim, em um conjunto estranho de circunstâncias que não são imediatamente óbvias para mim ... mas se eu encontrasse isso em código real, usaria técnicas comuns de depuração para descobrir como e por que estava fazendo o que estava fazendo e refatorar imediatamente o código para evitar essa situação ... mas mais importante: eu NUNCA escreveria absolutamente esse código em primeiro lugar, porque essa é a própria definição de código complicado, e me esforço para nunca escrever código complicado ".
Eu acho que alguns entrevistadores se ofenderiam com o fato de ser obviamente uma pergunta muito complicada, mas eu não me importo com desenvolvedores que tenham uma opinião, especialmente quando eles podem apoiá-la com um pensamento fundamentado e podem encaixar minha pergunta em uma declaração significativa sobre si mesmos.
fonte
Se você receber uma pergunta dessa entrevista (ou perceber algum comportamento igualmente inesperado em seu código), pense sobre que tipo de coisas poderia causar um comportamento que parece impossível à primeira vista:
Codificação : neste caso, a variável que você está vendo não é a que você pensa que é. Isso pode acontecer se você intencionalmente mexer com Unicode usando homóglifos ou caracteres de espaço para fazer o nome de uma variável parecer com outra, mas problemas de codificação também podem ser introduzidos acidentalmente, por exemplo, ao copiar e colar código da Web que contém código Unicode inesperado pontos (por exemplo, porque um sistema de gerenciamento de conteúdo fez algumas "formatações automáticas", como substituir
fl
por Unicode 'LATIN SMALL LIGATURE FL' (U + FB02)).Condições de corrida : Pode ocorrer uma condição de corrida , ou seja, uma situação em que o código não está sendo executado na sequência esperada pelo desenvolvedor. As condições de corrida geralmente acontecem no código com vários threads, mas vários threads não são um requisito para que as condições de corrida sejam possíveis - a assincronicidade é suficiente (e não se confunda, a assíncrona não significa que vários threads sejam usados sob o capô ).
Observe que, portanto, o JavaScript também não está livre de condições de corrida apenas porque é de thread único. Veja aqui um exemplo simples de thread único - mas assíncrono -. No contexto de uma única declaração, a condição de corrida, no entanto, seria bastante difícil de encontrar em JavaScript.
O JavaScript com trabalhadores da Web é um pouco diferente, pois você pode ter vários threads. O @mehulmpt nos mostrou uma ótima prova de conceito usando trabalhadores da web .
Efeitos colaterais : um efeito colateral da operação de comparação de igualdade (que não precisa ser tão óbvia como nos exemplos aqui, geralmente os efeitos colaterais são muito sutis).
Esse tipo de problema pode aparecer em muitas linguagens de programação, não apenas no JavaScript, por isso não estamos vendo um dos WTFs clássicos do JavaScript aqui 1 .
Obviamente, a pergunta da entrevista e as amostras aqui parecem muito bem-sucedidas. Mas eles são um bom lembrete de que:
1 Por exemplo, você pode encontrar um exemplo em uma linguagem de programação totalmente diferente (C #) exibindo um efeito colateral (óbvio) aqui .
fonte
Aqui está outra variação, usando uma matriz para exibir os valores desejados.
fonte
Ok, outro hack com geradores:
fonte
this
ser o objeto de janela)Usando Proxies :
Os proxies basicamente fingem ser um objeto de destino (o primeiro parâmetro), mas interceptam operações no objeto de destino (neste caso, a operação "get property") para que haja uma oportunidade de fazer algo diferente do comportamento padrão do objeto. Nesse caso, a ação "obter propriedade" é chamada
a
quando==
coagida seu tipo para compará-lo a cada número. Isto acontece:{ i: 0 }
, onde ai
propriedade é nosso contadora
a ==
comparação,a
o tipo de é coagido a um valor primitivoa[Symbol.toPrimitive]()
internamentea[Symbol.toPrimitive]
função usando o "get handler"Symbol.toPrimitive
, caso em que ele é incrementado e, em seguida, retorna o contador do objeto de destino:++target.i
. Se uma propriedade diferente estiver sendo recuperada, voltaremos a retornar o valor padrão da propriedade,target[name]
Assim:
Como na maioria das outras respostas, isso funciona apenas com uma verificação de igualdade flexível (
==
), porque verificações estritas de igualdade (===
) não fazem coerção de tipo que o Proxy possa interceptar.fonte
Symbol.toPrimitive
da mesma maneira em um objeto também funcionaria.Na verdade, a resposta para a primeira parte da pergunta é "Sim" em todas as linguagens de programação. Por exemplo, isso é no caso de C / C ++:
fonte
&&
para "e" lógico.O mesmo, mas diferente, mas ainda o mesmo (pode ser "testado" várias vezes):
Minha ideia partiu de como a equação do tipo de objeto Number funciona.
fonte
Uma resposta do ECMAScript 6 que utiliza símbolos:
Devido ao
==
uso, JavaScript é suposto coercea
em algo perto do segundo operando (1
,2
,3
neste caso). Porém, antes que o JavaScript tente descobrir por si só, ele tenta chamarSymbol.toPrimitive
. Se você fornecerSymbol.toPrimitive
JavaScript, usará o valor que sua função retornará. Caso contrário, o JavaScript chamariavalueOf
.fonte
Eu acho que este é o código mínimo para implementá-lo:
Criando um objeto fictício com um costume
valueOf
que incrementa uma variável globali
em cada chamada. 23 caracteres!fonte
Este usa o defineProperty com um bom efeito colateral causando variável global!
fonte
a
:get: (a => () => ++a)(0),
não é necessário global.Substituindo
valueOf
em uma declaração de classe, isso pode ser feito:O que acontece é que
valueOf
é chamado em cada operador de comparação. No primeiro,a
será igual1
, no segundo,a
será igual2
, e assim por diante, porque cada vez quevalueOf
é chamado, o valor dea
é incrementado.Portanto, o console.log será acionado e emitido (no meu terminal de qualquer maneira)
Thing: { value: 4}
, indicando que o condicional era verdadeiro.fonte