Soru Can (a == 1 && a == 2 && a == 3) hiç doğru olarak değerlendirilebilir mi?


Yönetici notu: Kodu düzeltmek veya bu bildirimi kaldırmak için lütfen dürtüye direnin. Beyaz boşluk modeli sorunun bir parçası olabilir ve bu nedenle gereksiz yere tahrif edilmemelidir. Eğer "boşluk anlamsız" kamptaysanız, kodu olduğu gibi kabul edebilmelisiniz.

Hiç mümkün mü (a== 1 && a ==2 && a==3) değerlendirebilir true JavaScript’te

Bu büyük bir teknoloji şirketi tarafından sorulan bir röportaj sorusudur. İki hafta oldu, ama yine de cevabı bulmaya çalışıyorum. Gündelik işimizde böyle bir kod yazmıyoruz, biliyorum ama merak ediyorum.


2253
2018-01-15 20:20


Menşei


Bu harika bir görüşme sorusu. Bu (ya da bunun gibi) kendimle hiç karşılaşmadım, ancak bağlantılı listelerde döngüler bulmakla ilgili duyduğumdan çok daha iyi. Hala yetersiz ve bu soruya bir başkasını diskalifiye etmem. Ancak, kesinlikle yetersiz bir şeyin devam ettiğini anlayabilecek adayları tercih ederim. - Draco18s
Bu, şirketin kod tabanı içinde yer alan kod türünün bir temsilcisi ise… - FeifanZ
Bu sadece müthiş bir görüşme sorusu ... - ghord
Görünüşe göre, bu gibi cloae oy veren insanlar için çok geniş: Javascript'te çok fazla geçerli cevap olduğunu söyleyen bir kazı mı? - tomsmeding
Yönetici notu: Yığın Taşması, söz konusu olana farklı dillerdeki cevaplarla insan kaynağına geçmişti. Bunlar Hangi soruyu cevaplamaya çalışır çünkü onlar farklı bir dilde olsa da genel sorunlara çözümlerdir. Lütfen onları "cevap değil" olarak işaretlemekten kaçının. Bunu söyledikten sonra, farklı dillerde daha fazla yanıt göndermekten lütfen çekinmeyin. Bu sorunun, diğer yanıtların bazılarına göre yorumlarda belirtildiği gibi JavaScript'e özgü bir nedeni vardır ve dile özgü sorularımızı beğenmemizin bir nedeni vardır. öyle kalmak. - BoltClock♦


Cevaplar:


Yararlanırsanız Nasıl == EserleriBasitçe bir nesneye sahip bir nesne oluşturabilirsiniz. toString (veya valueOf) her üç koşulda da tatmin edecek şekilde kullanıldığı zaman değiştiren işlevi.

const a = {
  i: 1,
  toString: function () {
    return a.i++;
  }
}

if(a == 1 && a == 2 && a == 3) {
  console.log('Hello World!');
}


Bunun nedeni, gevşek eşitlik operatörünün kullanılmasından kaynaklanmaktadır. Gevşek eşitlik kullanırken, işlenenlerden biri diğerinden farklıysa, motor diğerini dönüştürmeyi deneyecektir. Soldaki bir nesne ve sağdaki bir sayı durumunda, ilk çağrı ile nesneyi bir sayıya dönüştürmeyi dener. valueOf eğer heceli ise ve başarısızlığa uğrarsa toString. kullandım toString bu durumda sadece aklıma gelen şey olduğu için, valueOf daha anlamlı olur. Bunun yerine bir dizeden döndüğümde toStringMotor daha sonra biraz daha uzun bir yol olsa da, diziyi aynı sonucu veren bir sayıya dönüştürmeyi denerdi.


3097
2018-01-15 20:35



Bunu ima ederek değiştirebilir misiniz? valueOf() operasyon? - Sterling Archer
Evet, valueOf aynı nedenden dolayı toString yerine çalışır - Kevin B
Yorumlar uzun tartışma için değil; bu konuşma oldu sohbete taşındı. - deceze♦
Göre bu önce bir sayı dönüşümü denenecek valueOf biraz daha iyi. - Salman A
@Pureferret eşitliğinin karşılaştırmasının sol tarafındaki bir sayı değil, bir nesnedir. Bu nesnenin üzerinde bir sayı özelliği var i motoru rahatsız etmiyor. ;) - tomsmeding


Direnemedim - diğer cevaplar kuşkusuz doğrudur, ama aşağıdaki kodu geçemezsiniz:

var aᅠ = 1;
var a = 2;
var ᅠa = 3;
if(aᅠ==1 && a== 2 &&ᅠa==3) {
    console.log("Why hello there!")
}

İçindeki tuhaf boşluklara dikkat edin if deyim (sorunuzdan kopyaladım). Bu bir yarık karakter olarak ECMA komut dosyası tarafından yorumlanmayan bir Unicode uzay karakteri olan yarı genişlikte Hangul (bu tanıdık olanlar için Korece), yani bir tanımlayıcı için geçerli bir karakter olduğu anlamına gelir. Bu nedenle, Hangul'dan sonra a, ondan önce ve sonuncusu olan bir tamamen farklı üç değişken vardır. Alanı ile değiştirme _ okunabilirlik için, aynı kod şöyle görünecektir:

var a_ = 1;
var a = 2;
var _a = 3;
if(a_==1 && a== 2 &&_a==3) {
    console.log("Why hello there!")
}

Çıkış yapmak Mathias'ın değişken adı validatorundaki doğrulama. Bu tuhaf boşluk aslında sorularına dahil edilmiş olsaydı, bu tür bir cevap için bir ipucu olduğuna eminim.

Bunu yapma. Ciddi anlamda.

Düzenleme: (değişkeni başlatmasına izin verilmemesine rağmen) dikkatimi çekti. Sıfır genişlikli marangoz ve Sıfır genişlikli olmayan marangoz değişken isimlerde karakterlere de izin verilir - bkz. Sıfır genişlikli karakterlerle JavaScript'i şaşırtmak - artıları ve eksileri?.

Bu aşağıdaki gibi görünür:

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!")
}


1917
2018-01-16 05:14



Özgün sorudaki garip boşluklara bakılırsa, bence bu röportaj sorusunun cevap aradığı cevabın - boşluk gibi görünen boşluk olmayan karakterlerin kullanılması -. İyi nokta! - Baracus
@Baracus Bu cevabı hatırlatan Kevin'ın cevabı hakkındaki yorumunda garip bir boşluk olduğunu fark eden RonJohn'du, bu yüzden onu tespit etmek için kredi alamıyorum. Birkaç yıl önce bir blog yazısı yüzünden işimin etrafında gittiği için, şimdiye kadar bununla cevapsız kalmamıştım. Şimdiye kadar oldukça yaygın bir bilgi olduğunu varsaydım. - Jeff
Tabi ki bu bir yasak olarak yasaklandı. standart boşlukAynı zamanda röportajlar için de geçerlidir. [kaynak belirtilmeli] - Sanchises
Orijinal boşluk dikkate alındığında, daha da kötüsü olabilir, yani bir değişken var ᅠ2 = 3 kullanıldı; Yani üç değişken var aᅠᅠ= 1, ᅠ2 = 3, a = 3 (a␣ = 1, ␣2 = 3, a = 3, Böylece (a␣==1 && a==␣2 && a==3)) ... - Holger
@EdmundReed: Kaynak kodun içine girmeye çalışan bir karakter hayal edebiliyorum, ve sonra herkesin, bir hata bulmaya çalışan bir şeytanla karşılaştığını hayal edebiliyorum. (Özellikle Kore'de birileri kodluyorsa) - Martin Bonner


BU MÜMKÜN!

var i = 0;

with({
  get a() {
    return ++i;
  }
}) {
  if (a == 1 && a == 2 && a == 3)
    console.log("wohoo");
}

Bu, içindeki bir alıcıyı kullanır. with bildirmek a Üç farklı değeri değerlendirir.

... bu hala bu gerçek kodda kullanılması gerektiği anlamına gelmez ...


567
2018-01-15 20:35



Evet aynı şeyi deniyordum :) Yani röportajda doğru cevap şöyle olurdu: " benim kod kullanmam çünkü with." - Pointy
@Pointy - Ve sıkı modda programlıyorum with Müsade edilmez. - jfriend00
Kabul edilen cevapta @Pointy onlar olmadan benzer bir şey yaparlar with bu yüzden olabilir - Jungkook
@JonasW. Bir çok insan hala kullanıyor == ama görmedim with çünkü ... aslında "lütfen bunu kullanma" yazan JS belgelerinin dışında asla. Her neyse, hoş bir çözüm. - wortwart
@Pointy Bunu olmadan yapabilirsiniz with: stackoverflow.com/a/48288170/65387 - mpen


Alınanlar veya değer olmayan örnek:

a = [1,2,3];
a.join = a.shift;
console.log(a == 1 && a == 2 && a == 3);

Bu çünkü == çağırır toString hangi çağırır .join Diziler için.

Kullanarak başka bir çözüm Symbol.toPrimitive bir ES6 eşdeğeri toString/valueOf:

let a = {[Symbol.toPrimitive]: ((i) => () => ++i) (0)};

console.log(a == 1 && a == 2 && a == 3);


431
2018-01-17 11:37



without valueOfDaha iyi, daha dolaylı ama temelde aynı şey. - Jonas Wilms
Bu çözümü gerçekten çok beğendim çünkü nesnenin kendi katılma işlevini bir şeyden başka bir şeyle değiştirmiyorsunuz ve mantığın doğru olarak değerlendirilmesini sağlayan çok temiz ve okunması kolay bir hack. - Alex Pedersen
Dürüst olmak gerekirse, bunun en iyi cevap olduğunu düşünüyorum. Sıradan olmayan hiçbir şey içermez, sadece birkaç değer belirlenir. Temel JS bilgisi ile bile çok kolay anlaşılır. Aferin. - Zac Delventhal
Bu çok mantıklı, neredeyse yararlı geliyor. - Andrew
Çoğu cevapların suistimalle ilgili olacağını biliyordum. toString veya valueOf ama bu beni tamamen gardiyandan çıkardı. Çok akıllı ve aradığını bilmiyordum .joindahili olarak, ama tamamen mantıklı. - GBarroso


Eğer mümkün olup olmadığı sorulursa (Zorunlu değil), rastgele bir sayı döndürmek için “a” sorulabilir. 1, 2 ve 3 sıralı olarak üretilirse doğru olur.

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;
    }
  }
}


249
2018-01-16 06:21



- Bogojenerasyon - bogogenerasyon için mi? - Baldrickk
Diğer çözümleri bildiğim halde bile bu cevabı kasıtlı olarak verecektim, çünkü bu soruya cevap veriyor, ama sonunda oldukları şey değil. Aptal oyunları oynayın, aptal ödüller kazanın. - Edmund Reed
Peki ya 1000 den fazla deneme gerektiriyorsa? - Piyin
@Piyin 1000 den fazla deneme gerektirirse, bir ödül kazanırsınız! - Skeets
Bu cevabı beğeniyorum çünkü aşırı uçlara götürmek, bunun mümkün olduğunu gösteriyor. herhangi cpu'nun yazmaçları / önbelleği, program çalışırken yeterli kozmik ışınlarla vurulursa veya eğer kasıtlı olarak, eğer şartlı olarak başarısızlık dalının atlama zıplaması olmayacak şekilde bir güç hatası meydana getirirse, dil. - Ponkadoodle


Normal ifadeler olmadan hiçbir şey yapamayacağınız zaman:

var a = {
  r: /\d/g, 
  valueOf: function(){
    return this.r.exec(123)[0]
  }
}

if (a == 1 && a == 2 && a == 3) {
    console.log("!")
}

Özel nedeniyle çalışır valueOf Nesne ilkel ile karşılaştırıldığında (Sayı gibi) çağrılan yöntem. Ana numara bu a.valueOf her seferinde yeni bir değer döndürüyor çünkü arama yapıyor exec düzenli ifadeyle g güncelleştirmeye neden olan bayrak lastIndex Bu düzenli ifadenin her zaman eşleşmesi bulunur. Yani ilk kez this.r.lastIndex == 0, uyumlu 1 ve güncellemeler lastIndex: this.r.lastIndex == 1, bir dahaki sefere regex uyuşacak 2 ve bunun gibi.


196
2018-01-16 19:35



Umm .. bu nasıl çalışır? - Abdillah
@Abdillah bir regex nesnesi, eşleştiği son endeksi hatırlayacak exec yine bu dizinden arama yapmaya başlayacak. MDN çok açık değil. - Simon Chan
Görüyorum this.r regex nesnesi durumu / endeksi hatırlar. Teşekkürler! - Abdillah
! - Patrick Roberts
Bir dizeye geçmek için tavsiye ederim exec olsa da, belirtilecek bir tamsayı değil. - Bergi


Küresel kapsamda aşağıdakiler kullanılarak gerçekleştirilebilir. İçin nodejs kullanım global yerine window Aşağıdaki kodda.

var val = 0;
Object.defineProperty(window, 'a', {
  get: function() {
    return ++val;
  }
});
if (a == 1 && a == 2 && a == 3) {
  console.log('yay');
}

Bu cevap, değişkeni almak için bir alıcı tanımlayarak, yürütme bağlamında global kapsam tarafından sağlanan örtük değişkenleri kötüye kullanır.


183
2018-01-15 20:37



Bu varsayılmaktadır a bir özelliğidir thisöyle görünmüyor. Eğer a Yerel bir değişkendi (benziyor), o zaman işe yaramazdı. - jfriend00
@ jfriend00 demek eğer var eğer bir var; yere? - jontro
Evet. başvurma a == 1 daha çok a bir değişken, bir özellik değil this. Her ikisinin de doğru olabileceği globals gibi bir oddball yer olsa da, genellikle, bir değişken ile bildirmek var a veya let a hayır demek yok this Bu size erişmenizi sağlar a kod gibi bir özellik olarak varsayar. Yani, kodun görünüşte bazı garip küresel değişken şeyleri varsayıyor. Örneğin, kodunuz node.js'de çalışmıyor ve bir işlev içinde katı modda çalışmıyor. Tam olarak nerede çalıştığını belirtmeli ve neden işe yaradığını açıklamalısınız. Aksi halde yanıltıcıdır. - jfriend00
@ jfriend00 iyi elbette. Diğer yanıtlarla birlikte çok daha fazla değer katacağından emin değil. Cevabı günceller - jontro
Soru şu ki, bu "hiç" doğru olabilirdi. Ve cevap evet, ve bu doğru olabileceği senaryolardan biri: a yerel bir değişken değildir ve global kapsamda artan bir alıcıyla tanımlanır. - Zac Delventhal


Bu değişken durumunda mümkündür a Erişim sağlandığında, 2 web çalışanı bir SharedArrayBuffer aracılığıyla ve ayrıca bazı ana komutlarla söylenir. Olasılık düşüktür, ancak kod makine koduna derlendiğinde, web çalışanlarının değişkeni güncellemesi mümkündür. a tam zamanında şartlar a==1, a==2 ve a==3 tatmin edici.

Bu, web çalışanları ve JavaScript'te SharedArrayBuffer tarafından sağlanan çok iş parçacıklı ortamlarda bir yarış durumu örneği olabilir.

İşte yukarıdaki temel uygulama:

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 Air'ımda, ilk denemede yaklaşık 10 milyar yinelemeden sonra gerçekleşir:

enter image description here

İkinci deneme:

enter image description here

Söylediğim gibi, şanslar düşük olacak, ama yeterli zaman verildiği takdirde, bu duruma vuracak.

İpucu: Sisteminizde çok uzun sürerse. Sadece dene a == 1 && a == 2 ve değişim Math.random()*3 için Math.random()*2. Daha fazla ve daha fazla liste eklemek isabet şansını azaltır.


171
2018-01-17 07:39



Dürüst olmak gerekirse, bu en iyi cevaptır. Diğer bütün cevaplar, bilinçsiz bir şey yapmak için kasıtlı bir girişimde bulunmayı gerektirir. Bu cevap aslında gerçek dünyada olabilecek bir şeyi - bir yarış koşulunu yansıtır. - Tom Swirly
Sadece bu da değil - Bunun gerçek dünyada olduğunu gördüm. Sorudaki kesin koşulla değil, bir fonksiyonun başlangıcında (a == 1) ve fonksiyonun daha sonra (a == 2) kontrol edilmesi ve her iki koşulun da kodun vurulması ile kesinlikle. FYI, bunu ilk kez gördüğümde araba motor kontrolörü vardı ve kodlama standartlarını yerine koyduk. İkinci sefer askeri uçaklar için bir saman ve flare dağıtıcı sistemde ve benim şirkette ilk gün Bunu buldum ve tamir ettim, ekibin geri kalanı hala sorunu tartışıyordu. (Kudos seviyesi: yüksek! :) - Graham
Yani, web çalışanları ile javascript programlanmış "araba motoru kontrolörleri" ve "chaff ve parlama dağıtıcı sistemleri" üzerinde çalıştı? Sanırım tekrar dışarı çıkacağım. - psaxton
@psaxton :) Tabii ki değil - ama biz paylaşımlı verileri ile çok iş parçacıklı yazılım var. Bu, Javascript veya web çalışanlarına özgü olmayan tüm çok iş parçacıklı yazılımlar için bir anti-desentir. Montaj dilinde, Brainf * ck, Visual BASIC, C veya Javascript ile programlama yapmanın bir önemi yoktur - eğer bunu çok iş parçacıklı bir uygulamada paylaşılmış veri ile yaparsanız her zaman başarısız. - Graham
Sanırım bu, @ jontro'nun cevabı etrafında ayrıntılı bir sarmalayıcı. - qntm


Bu, bir dizi kendiliğinden örenci kullanarak da mümkündür:

(Bu jontro'nun çözümüne benzer, ancak bir sayaç değişkeni gerektirmez.)

(() => {
    "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.");
    }
})();


141
2018-01-16 11:37



Bir getter kullanma yaklaşımı da ile çalışır unutmayın ===değil, sadece ==. - Makyen
Bunun daha az girinti ile çalıştığını unutmayın. - Evert
Bu aşırı ... - Patrick Roberts
Bu çözüm dayanır this ok işlevinin gövdesindeki genel nesne olmak. - Roy Tinker
@PatrickRoberts Ve diğer her şey burada değil mi? - Midnightas


Bu cevabı zaten yayınlanmış görmüyorum, bu yüzden bunu miksata atacağım. Bu benzer Jeff'in cevabı yarı genişlikte Hangul alanı ile.

var a = 1;
var a = 2;
var а = 3;
if(a == 1 && a == 2 && а == 3) {
    console.log("Why hello there!")
}

İkincisi ile biraz çelişki fark edebilirsiniz, ancak birinci ve üçüncü çıplak gözle özdeştir. Her 3 ayrı karakter:

a - Latin küçük harf A
 - Tam Genişlik Latin küçük harf A
а - Kiril küçük harf A

Bunun için genel terim "homojen" dir: aynı görünen farklı unicode karakterler. Genellikle almak zor üç Bu tamamen ayırt edilemez, ancak bazı durumlarda şanslı olabilirsiniz. A, Α, А ve Ꭺ daha iyi çalışırdı (Latin-A, Yunan alfabesi, Kril-A, ve Cherokee-A sırasıyla; ne yazık ki Yunan ve Cherokee küçük harfleri Latin'den çok farklı a: α,ve bu nedenle yukarıdaki snippet ile yardımcı olmaz).

Orada en yaygın sahte alan adlarında bir sınıf Homoglyph Attacks var. wikipediа.org (Kiril) vs wikipedia.org (Latin)), ancak kod içinde de gösterebilir; genellikle underhanded olarak adlandırılır (bir yorumda belirtildiği gibi, [Gizli] sorular artık konu dışı PPCGama bu tür şeylerin ortaya çıkabileceği bir meydan okuma türü olarak kullanılırdı. kullandım bu web sitesi Bu cevap için kullanılan homoglifleri bulmak.


125
2018-01-16 18:44



"Hafif tutarsızlık" Ben böyle demezdim. - hvd
@ hvd Tamamen yazı tipi oluşturmaya bağlıdır. Gördüğüm şey bu. - Draco18s
Bu durumda üçüncü bir seçenek istedin. - JakeSteam
@Jake Yeah, Tam Width Latin küçük harf A en büyük homoglif değil (ama büyük harfli varyantlar şaşırtıcı). Genel olarak istenen etkiyi elde etmek için sadece iki taneye ihtiyacınız vardır. - Draco18s
Unicode varyant seçiciyi de kullanabilirsiniz (U + FE00..U + FE0F). Bunların hiçbiri a: a︀  a︁  a︂. Tutarsızlıklar hakkında endişelenme. - Salman A


Alternatif olarak, bunun için bir sınıf ve çek için bir örnek kullanabilirsiniz.

function A() {
    var value = 0;
    this.valueOf = function () { return ++value; };
}

var a = new A;

if (a == 1 && a == 2 && a == 3) {
    console.log('bingo!');
}

DÜZENLE

ES6 sınıflarını kullanarak böyle görünecekti

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!');
}


113
2018-01-16 15:11



sadece function A() {value = 0; başlangıçta? - Dave C