!! ~ (틸드 / 뱅뱅 틸드가 아님)는 '포함 / 포함'배열 메서드 호출의 결과를 어떻게 변경합니까?


95

여기 jQuery inArray페이지 의 주석을 읽으면 흥미로운 선언이 있습니다.

!!~jQuery.inArray(elm, arr) 

이제 이중 느낌표가 결과를 boolean값이있는 type으로 변환 할 것이라고 믿습니다 true. 내가 이해하지 못하는 것은이 모든 것에서 물결표 ( ~) 연산자를 사용하는 것입니다.

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

if진술 리팩토링 :

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

고장:

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

또한 물결표를 앞에 넣으면 결과가 -2.

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

여기서 물결표의 목적을 이해하지 못합니다. 누군가가 그것을 설명하거나 리소스를 가리킬 수 있습니까?


50
그런 코드를 작성하는 사람은 키보드에서 물러나야합니다.
Kirk Woll 2012

12
@KirkWoll : 왜? ~jQuery.inArray()실제로 매우 유용합니다. 검색 기능 -1이 실패를 반환하는 이유 (2의 보수가 거짓 인 유일한 값) 일 수도 있습니다. 트릭을보고 이해하면 != -1.
Amadan

9
@Amadan-아니. 안돼. 진지하게, 나는 당신이 무엇이든 방어 !!~하고 있다는 것을 믿을 수 없습니다 .
Kirk Woll

24
문제는 그저 "속임수"입니다. if (x != -1)if (~x)나에게 가장 큰 차이점 은 전자가 실제로 당신이하려는 일을 표현한다는 것입니다. 후자는 완전히 다른 작업을 원한다는 것을 나타냅니다 ( "내 64 비트 숫자를 32 비트 정수로 변환하고 해당 정수의 비트가 아닌지 확인하십시오"). 여기서 원하는 결과를 얻을 수 있습니다. 하나의 케이스.
JimmiTh

10
>= 0아마 아니었다 리트 더 많은 비밀이 충분히 그래서이 !!~사용되었다.
Yoshi

답변:


56

물결표 연산자는 실제로 jQuery의 일부가 아닙니다. JavaScript 자체에서 비트 NOT 연산자입니다.

The Great Mystery of the Tilde (~)를 참조하십시오 .

정수에 대해 비트 논리 연산을 수행하고 있기 때문에 실험에서 이상한 숫자를 얻습니다 (내가 아는 한 2의 보수 또는 이와 비슷한 것으로 저장 될 수 있습니다 ...)

2의 보수 는 숫자를 이진수로 표현하는 방법을 설명합니다. 내가 옳았다 고 생각합니다.


3
결정된! (이상하게도 내 원래 답변 이후에 작성된 다른 링크로 변경했습니다 ...)
pglhall

121

.NET Framework ~앞에 적용될 수있는 특별한 이유가 있습니다 $.inArray.

원래,

~$.inArray("foo", bar)

할 수있는 더 짧은 방법입니다

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

$.inArray첫 번째 인수가 발견되면 배열에있는 항목의 인덱스를 반환하고 발견되지 않으면 -1을 반환합니다. 즉, "이 값이 배열에 있습니까?"라는 부울을 찾는 경우 -1이 진실 값이고 $ .inArray가 0 (잘못된 값)을 반환 할 때 부울 비교를 수행 할 수 없습니다. ), 그것은 배열의 첫 번째 요소에서 실제로 발견되었음을 의미합니다.

적용 ~비트 연산자하는 원인이 -1되기 위해 0, 그리고`가 0 원인 -1. 따라서 배열에서 값을 찾지 못하고 비트 NOT을 적용하면 잘못된 값 (0)이 발생하고 다른 모든 값은 0이 아닌 숫자를 반환하고 진실한 결과를 나타냅니다.

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

그리고 의도 한대로 작동합니다.


2
브라우저에서 얼마나 잘 지원됩니까 (현재 2014 년입니까?) 아니면 계속 완벽하게 지원 되었습니까?
Explosion Pills

이와 같은 기본 작업이 완벽하지 않으면 놀랄 것입니다.
pcarvalho

104

!!~expr그렇지 않은 false경우 expr로 평가됩니다 . 와 동일하지만 깨짐 *-1true
expr != -1


JavaScript 비트 연산 은 피연산자를 2의 보수 형식으로 부호있는 32 비트 정수로 변환 하기 때문에 작동 합니다. 따라서 !!~-1다음과 같이 평가됩니다.

   -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

이외의 값 -1은 하나 이상의 비트를 0으로 설정합니다. 반전하면 진실한 가치가 생성됩니다. !진실 값에 연산자를 두 번 적용하면 부울 true가 반환됩니다.

와 함께 사용할 때 .indexOf()결과가 다음 -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

* !!~8589934591거짓으로 평가되므로질색을 (를) 테스트하는 데 안정적으로 사용할 수 없습니다 -1.


1
안정된 라이브러리에서는를 사용하는 데 아무런 문제가 ~foo.indexOf(bar)없습니다. 문자 나 성능이 크게 절약되지는 않지만 동일한 방식으로 비교적 일반적인 속기 foo = foo || {}입니다.
zzzzBov

6
그것은 문제가 아닙니다 ... 적어도 다른 사람이 당신의 코드를 계속하도록 요청받을 때까지는 아닙니다.
Salman A


1
@ahsteele, 나는 그 규칙을 잘 알고 있지만 비트 연산자는 내가 생각할 수있는 모든 프로그래밍 언어의 일부입니다. 코드를 읽을 수 있는 사람이 읽을 수있는 방식으로 프로그래밍하려고합니다 . 다른 사람이 이해하지 못한다고해서 단순히 언어의 기능을 사용하는 것을 멈추지 않습니다. 그렇지 않으면를 사용할 수도 없습니다!! .
zzzzBov

엄밀히 말하면, >= 0같은 동작을하지 않습니다 !!~. !== -1더 가깝습니다.
Peter Olson

33

~foo.indexOf(bar)함수가 존재하지 않기 foo.contains(bar)때문에 표현하는 일반적인 속기 contains입니다.

일반적으로 "거짓"값이라는 JavaScript의 개념으로 인해 부울로 캐스트 할 필요가 없습니다. 이 경우 함수의 출력을 true또는 로 강제하는 데 사용됩니다 false.


6
+1이 답변은 허용 된 답변보다 "이유"를 더 잘 설명합니다.
nalply 2010 년

18

jQuery.inArray()-1보수 ( ~)가 인 "찾을 수 없음"을 반환 합니다 0. 따라서 "찾을 수 없음"에 대해서는 ~jQuery.inArray()거짓 값 ( 0)을 반환하고 "발견됨"에 대해서는 진실 값 (음의 정수)을 반환합니다. !!그런 다음 거짓 / 진정한 것을 실제 부울 false/ 로 공식화합니다 true. 따라서 "발견됨"및 "찾을 수 없음"에 대해 !!~jQuery.inArray()제공 true합니다 false.


13

~4 바이트는 int이 수식 같다-(N+1)

그래서

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

3
(예를 들어)이므로 항상 사실은 아닙니다 ~2147483648 != -(2147483648 + 1).
Frxstrem

10

~연산자는 비트 보수 연산자입니다. 의 정수 결과 inArray()는 요소를 찾을 수없는 경우 -1이거나 음이 아닌 정수입니다. -1의 비트 보수 (2 진수로 모두 1 비트로 표시)는 0입니다. 음이 아닌 정수의 비트 보수는 항상 0이 아닙니다.

따라서 !!~itrue정수 "I"는 음이 아닌 정수이고, 경우 false에 "i"정확히 언제 -1.

참고 ~항상 정수 피연산자를 강제 변환; 즉, 정수가 아닌 부동 소수점 값을 숫자가 아닌 값뿐만 아니라 정수로 강제 적용합니다.


10

물결표는 비트 단위가 아닙니다. 값의 각 비트를 반전합니다. 일반적으로 ~숫자에 사용하면 부호가 반전되고 1이 뺍니다.

따라서를 수행 ~0하면 -1이됩니다 (반전 된 0은 -0, 빼기 1은 -1).

본질적으로 항상 부울 인 값을 얻기위한 정교하고 초 미세 최적화 된 방법입니다.


8

당신 말이 맞습니다 :이 코드는 호출이 -1을 반환 false할 때 반환 됩니다 indexOf. 그렇지 않으면 true.

당신이 말했듯이, 다음과 같은 것을 사용하는 것이 훨씬 더 현명 할 것입니다.

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

1
하지만 클라이언트에 보낼 3 바이트가 더 있습니다! 편집 : (그냥 농담, 내 의견을 게시하고 그것이 분명하지 않다는 것을 깨달았습니다 (슬프고 어리 석습니다))
Wesley Murch

@Wesley : 맞습니다.하지만 클라이언트가 .NET Framework 를 캐시한다고 가정하면 각 클라이언트에 한 번만 전송 하면됩니다 .js. 그런 말을하는 데, 그들이 사용할 수있는 >=0것이 아니라 !==-1- 더 추가 바이트를 보낼과 비트 만지작 버전보다 여전히 더 읽을 수 있습니다.
LukeH

2
누가 여기를 트롤링하고 있습니까? ;) 나는 읽을 수있는 코드를 작성하는 것이 이런 종류의 질문을 생성하는 사전 최적화 된 암호보다 낫다는 것을 당연한 것으로 생각합니다. 나중에 축소하고 지금 읽고 이해할 수있는 코드를 작성하십시오.
Wesley Murch

2
개인적으로 나는 그것이 > -1훨씬 더 읽기 쉽다고 말하고 싶지만 그것은 아마도 매우 주관적 일 것입니다.
Yoshi

6

~연산자는 비트 NOT 연산자입니다. 이것이 의미하는 바는 이진 형식의 숫자를 취하고 모든 0을 1로, 1을 0으로 변환한다는 것입니다.

예를 들어, 이진수 0은 0000000이고 -1은 11111111입니다. 마찬가지로 1은 00000001이진수이고 -2는 11111110.


3

내 생각 엔 그것이 몇 글자 더 짧기 때문에 거기에 있다는 것입니다 (도서관 저자는 항상 뒤에 있습니다). 또한 네이티브 코드로 컴파일 할 때 몇 번의 머신 사이클 만 사용하는 작업을 사용합니다 (숫자 비교와 반대).

나는 그것이 과잉이지만 아마도 빡빡한 루프에서 의미가있을 수 있다는 또 다른 대답에 동의합니다 (성능 이득 추정이 필요하지만 그렇지 않으면 조기 최적화로 판명 될 수 있습니다.)


2

비트 연산이기 때문에 경로가 modifiedPaths에 나타나는지 확인하는 가장 빠른 (계산적으로 저렴한) 방법이라고 가정합니다.


1

으로 (~(-1)) === 0:

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

1
이것은 정확할 수 있지만 질문자에게 유용한 설명입니까? 전혀. 처음부터 이해하지 못했다면 이와 같은 간결한 대답은 도움이되지 않습니다.
Spudley

이 대답이 의미가 있다고 생각합니다. 수학적 두뇌가 있다면 각 단계에서 어떤 부분이 변하는 지 명확하게 볼 수 있습니다. 그것은이다 최선 이 질문에 대한 대답은? 아니요.하지만 유용하다고 생각합니다! +1
Taylor Lopez
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.