!! ~ (tilde / bang bang tilde değil) 'içerir / dahil' bir dizi yöntemi çağrısının sonucunu nasıl değiştirir?


95

Buradaki jQuery inArraysayfasındaki yorumları okursanız, ilginç bir beyan var:

!!~jQuery.inArray(elm, arr) 

Şimdi, çift ünlem işaretinin sonucu booleandeğerine sahip türe çevireceğine inanıyorum true. Anlamadığım şey, tüm bunlarda tilde ( ~) operatörünün kullanımı nedir?

var arr = ["one", "two", "three"];
if (jQuery.inArray("one", arr) > -1) { alert("Found"); }

İfadeyi yeniden düzenleme if:

if (!!~jQuery.inArray("one", arr)) { alert("Found"); }

Yıkmak:

jQuery.inArray("one", arr)     // 0
~jQuery.inArray("one", arr)    // -1 (why?)
!~jQuery.inArray("one", arr)   // false
!!~jQuery.inArray("one", arr)  // true

Ayrıca tilde işaretini önüne koyarsam sonucun olacağını da fark ettim -2.

~!!~jQuery.inArray("one", arr) // -2

Burada tilde'nin amacını anlamıyorum. Lütfen birisi bunu açıklayabilir mi veya beni bir kaynağa yönlendirebilir mi?


50
Böyle bir kod yazan kişinin klavyeden uzaklaşması gerekir.
Kirk Woll

12
@KirkWoll: Neden? ~jQuery.inArray()aslında çok kullanışlıdır - muhtemelen arama işlevlerinin -1başarısızlık için geri dönmesinin çok iyi bir nedeni (ikisinin tümleyeni yanlış olan tek değer). Numarayı görüp anladıktan sonra, bundan daha okunabilir olduğunu hissediyorum != -1.
Amadan

9
@Amadan - hayır. Sadece hayır. Cidden, sana savunan inanamıyorum !!~için bir şey .
Kirk Woll

24
Sorun şu ki, sadece bir "numara". Benim için if (x != -1)ve arasındaki temel fark if (~x), ilkinin aslında ne yapmak istediğinizi ifade etmesi. İkincisi, tamamen başka bir şey yapmak istediğinizi ifade eder ("lütfen 64 bitlik Sayımı 32 bitlik bir tam sayıya dönüştürün ve bu tamsayının bitsel DEĞİL OLUP OLMADIĞINI kontrol edin") burada istediğiniz sonucu elde edersiniz. Bir vaka.
JimmiTh

10
>= 0Muhtemelen değildi leet daha şifreli böylece yeterince !!~kullanıldı.
Yoshi

Yanıtlar:


57

Tilde operatörü aslında jQuery'nin bir parçası değildir - JavaScript'in kendisinde bitsel bir NOT operatörüdür.

The Great Mystery of the Tilde (~) bölümüne bakın .

Deneylerinizde garip sayılar alıyorsunuz çünkü bir tamsayı üzerinde bit düzeyinde mantıksal bir işlem gerçekleştiriyorsunuz (ki bu, tüm bildiğim, ikinin tümleyicisi veya bunun gibi bir şey olarak saklanabilir ...)

İkinin tümleyicisi , bir sayının ikili olarak nasıl temsil edileceğini açıklar. Sanırım haklıydım.


3
Sabit! (
Garip bir şekilde

121

Bazen ~önünde uygulandığını görmenin özel bir nedeni var $.inArray.

Temel olarak,

~$.inArray("foo", bar)

yapmanın daha kısa yolu

$.inArray("foo", bar) !== -1

$.inArrayİlk bağımsız değişken bulunursa dizideki öğenin dizinini döndürür ve bulunamazsa -1 döndürür. Bu, "dizide bu değer mi?" Boole'ini arıyorsanız, -1 doğru bir değer olduğundan ve $ .inArray 0 (yanlış bir değer ), aslında dizinin ilk elemanında bulunduğu anlamına gelir.

Başvuru ~bit seviyesinde operatörü neden -1olmak için 0, ve, 'olmak için 0 neden -1. Bu nedenle, dizideki değeri bulamamak ve bit düzeyinde NOT uygulamak yanlış bir değerle (0) sonuçlanır ve diğer tüm değerler 0 olmayan sayılar döndürür ve doğru bir sonucu temsil eder.

if (~$.inArray("foo", ["foo",2,3])) {
    // Will run
}

Ve amaçlandığı gibi çalışacak.


2
Bu tarayıcılarda ne kadar iyi destekleniyor (şimdi 2014'te mi?) Yoksa başından beri mükemmel bir şekilde desteklendi mi?
Patlama Hapları

Bunun gibi temel işlemler mükemmel olmazsa şaşırırdım.
pcarvalho

105

!!~exprfalsene zaman exprbaşka -1türlü olduğunu değerlendirir true.
Aynı expr != -1, sadece kırık *


JavaScript bitsel işlemleri , işlenenleri ikinin tümleme biçiminde 32 bitlik işaretli tamsayılara dönüştürdüğü için çalışır . Böylece !!~-1şu şekilde değerlendirilir:

   -1 = 1111 1111 1111 1111 1111 1111 1111 1111b // two's complement representation of -1
  ~-1 = 0000 0000 0000 0000 0000 0000 0000 0000b // ~ is bitwise not (invert all bits)
   !0 = true                                     // ! is logical not (true for falsy)
!true = false                                    // duh

Dışında bir değer -1, sıfıra ayarlanmış en az bir bite sahip olacaktır; tersine çevirmek doğru bir değer yaratacaktır; !operatörü doğru bir değere iki kez uygulamak , boolean true döndürür.

İle kullanıldığında .indexOf()ve sadece sonucun olup olmadığını kontrol etmek istiyoruz -1:

!!~"abc".indexOf("d") // indexOf() returns -1, the expression evaluates to false
!!~"abc".indexOf("a") // indexOf() returns  0, the expression evaluates to true
!!~"abc".indexOf("b") // indexOf() returns  1, the expression evaluates to true

* !!~8589934591yanlış olarak değerlendirilir, dolayısıyla buiğrenmegüvenilir bir şekilde test etmek için kullanılamaz -1.


1
Kararlı bir kitaplıkta, kullanımla ilgili bir sorun görmüyorum ~foo.indexOf(bar), karakterlerde veya performansta önemli bir tasarruf değil, ancak aynı şekilde nispeten yaygın bir kısaltmadır foo = foo || {}.
zzzzBov

6
Bu bir sorun değildir ... en azından bir başkasından kodunuzu kullanmaya devam etmesi istenene kadar.
Salman A


1
@ahsteele, bu kuralın farkındayım, ancak bitsel operatörler aklıma gelen her programlama dilinin bir parçası. Kodu okuyabilen biri tarafından okunabilecek bir şekilde programlamaya çalışıyorum . Bir dilin özelliklerini sadece başkası anlamadığı için kullanmayı bırakmıyorum, aksi takdirde kullanamam bile!! .
zzzzBov

Kesinlikle konuşursak, >= 0aynı davranışa sahip değildir !!~. !== -1daha yakın.
Peter Olson

33

~foo.indexOf(bar)temsil edecek bir ortak kısaltmasıdır foo.contains(bar)çünkü containsişlevi yok.

Tipik olarak boolean'a çevrim, JavaScript'in "yanlış" değerler kavramı nedeniyle gereksizdir. Bu durumda, fonksiyonun çıktısını trueveya olmaya zorlamak için kullanılır false.


6
+1 Bu cevap, "neden" i kabul edilen cevaptan daha iyi açıklıyor.
nalply

18

jQuery.inArray()-1tamamlayıcısı ( ~) olan "bulunamadı" için döner 0. Böylece, "bulunamadı" için ~jQuery.inArray()yanlış bir değer ( 0) ve "bulundu" için doğru bir değer (negatif bir tam sayı) döndürür. !!daha sonra falsy / truey'yi gerçek boolean false/ şeklinde biçimlendirecektir true. Yani, "bulundu" ve "bulunamadı" için !!~jQuery.inArray()verilecek .truefalse


13

~Tüm 4 bayt intbu formüle eşittir-(N+1)

YANİ

~0   = -(0+1)   // -1
~35  = -(35+1)  // -36 
~-35 = -(-35+1) //34 

3
Bu her zaman doğru değildir, çünkü (örneğin) ~2147483648 != -(2147483648 + 1).
Frxstrem

10

~Operatör bit düzeyinde tamamlayıcı operatörüdür. Tam sayı sonucu inArray(), öğe bulunamadığında -1 veya negatif olmayan bir tam sayıdır. -1'in bitsel tamamlayıcısı (tüm 1 bit olarak ikili olarak temsil edilir) sıfırdır. Negatif olmayan herhangi bir tamsayının bitsel tamamlayıcısı her zaman sıfırdan farklıdır.

Böylece !!~iolacak truetamsayı "i", negatif olmayan bir tam sayı olduğu zaman, ve false"i" tam olarak ne zaman -1.

Not ~hep tamsayıya onun işlenen coerces; yani, tamsayı olmayan kayan noktalı değerleri hem tamsayıya hem de sayısal olmayan değerlere zorlar.


10

Tilde bit düzeyinde DEĞİLDİR - değerin her bitini tersine çevirir. Genel bir kural olarak ~, bir sayı üzerinde kullanırsanız , işareti tersine çevrilecek ve ardından 1 çıkarılacaktır.

Böylece, bunu ~0yaptığınızda -1 elde edersiniz (ters 0, -0, 1 çıkarma -1'dir).

Esasen her zaman Boole olan bir değer elde etmenin ayrıntılı, süper mikro optimize edilmiş bir yoludur.


8

Haklısınız: Bu kod dönecektir falsezaman indexOfçağrı döner -1; aksi takdirde true.

Dediğin gibi, şöyle bir şey kullanmak çok daha mantıklı olurdu

return this.modifiedPaths.indexOf(path) !== -1;

1
Ancak müşteriye gönderilecek 3 bayt daha! düzenleme: (bu arada sadece şaka yaptım, yorumumu yayınladı ve açık olmadığını fark etti (ki bu hem üzücü hem de aptalca)
Wesley Murch, 14'12

@Wesley: Bu doğru, ancak istemcinin önbelleğe alacağını varsayarak her istemciye yalnızca bir kez gönderilmesi gerekiyor .js. Bunu söyledikten sonra, göndermek için fazladan bayt kullanmaktan >=0ziyade kullanabilirler !==-1ve yine de bit çeviren sürümden daha okunabilir.
LukeH

2
Burada kim kimi trol ediyor? ;) Okunabilir kod yazmanın, bu tür soruları üreten şifreli önceden optimize edilmiş koddan daha iyi olduğunu kabul ettim sanırım. Daha sonra küçültün ve şimdi okunabilir, anlaşılır kod yazın.
Wesley Murch

2
Şahsen bunun > -1daha okunabilir olduğunu söyleyebilirim , ancak bu muhtemelen çok özneldir.
Yoshi

6

~Operatör bitsel DEĞİL operatörüdür. Bunun anlamı, ikili formda bir sayı alması ve tüm sıfırları birlere ve birleri de sıfıra dönüştürmesidir.

Örneğin, ikili sayıdaki 0 ​​sayısı 0000000, -1 ise 11111111. Aynı şekilde, 1 00000001ikilide, -2 ise 11111110.


3

Tahminim, birkaç karakter daha kısa olduğu için (hangi kütüphane yazarları her zaman peşinde) orada olduğu. Ayrıca, yerel kodda derlendiğinde (bir sayı ile karşılaştırmanın aksine) yalnızca birkaç makine döngüsü alan işlemleri kullanır.

Bunun bir aşırı öldürme olduğuna, ancak dar bir döngüde belki de mantıklı olabileceğine dair başka bir yanıta katılıyorum (performans kazancı tahmini gerektirir, ancak aksi takdirde erken optimizasyon olabilir.)


2

Bitsel bir işlem olduğu için, yolun değiştirilmiş Yollarda görünüp görünmediğini kontrol etmenin en hızlı (hesaplama açısından ucuz) yolu olduğunu varsayıyorum.


1

Öyle (~(-1)) === 0ki:

!!(~(-1)) === Boolean(~(-1)) === Boolean(0) === false

1
Bu doğru olabilir, ancak soru soran için faydalı bir açıklama mı? Bir şey değil. Başlamak için anlamasaydım, bunun gibi kısa bir cevap yardımcı olmazdı.
Spudley

Bu cevabın mantıklı olduğunu düşünüyorum. Matematiksel bir beyniniz varsa, her adımda hangi parçaların değiştiğini açıkça görebilirsiniz. Öyle mi iyi bu sorunun cevabı? Hayır. Ama faydalı olduğunu düşünüyorum! +1
Taylor Lopez
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.