JavaScript >>> 연산자 란 무엇이며 어떻게 사용합니까?


150

필터 메소드를 Array에 추가하는 Mozilla 코드를 보았는데 혼란 스러웠습니다.

var len = this.length >>> 0;

>>> 전에 JavaScript에서 사용 된 적이 없습니다.
그것은 무엇이며 무엇을합니까?


@CMS 사실,이 코드 / 질문은 이것에서 나옵니다. 그러나 여기의 답변은 이전 답변보다 더 구체적이고 가치가 있습니다.
저스틴 존슨

2
또는 버그이거나 모질라 사람들이 this.length가 -1 일 수 있다고 가정합니다. >>>는 부호없는 시프트 연산자이므로 var len은 항상 0 이상입니다.
user347594

1
애쉬 Searle은 그것의 사용을 발견 - JS (더그 크록 포드)의 군주를 전복의 구현에 Array.prototype.push/ Array.prototype.pop- hexmen.com/blog/2006/12/push-and-pop (그는 시험, 하하를했다하지만).
Dan Beam

답변:


211

숫자가 아닌 숫자를 숫자로 변환하는 것이 아니라 부호없는 32 비트 정수로 표현할 수있는 숫자로 변환합니다.

자바 스크립트의 숫자가 배정 밀도 수레 (*)는 비트 연산자가 있지만 ( <<, >>, &, |~ )는 32 비트 정수에 대한 운영의 관점에서 정의된다. 비트 단위 연산을 수행하면 계산을 수행 한 다음 숫자로 다시 변환하기 전에 숫자를 32 비트 부호있는 정수로 변환하여 32보다 작은 분수와 상위 비트를 잃게됩니다.

따라서 0 비트의 오른쪽 이동과 같이 실제 효과없이 비트 단위 연산을 수행하면 >>0숫자를 반올림하여 32 비트 int 범위에있게됩니다. 또한 삼항 >>>연산자는 부호없는 연산을 수행 한 후 계산 결과를 다른 사람이하는 부호있는 정수가 아닌 부호없는 정수로 Number로 변환하므로 음수를 32 비트 2의 보수로 변환하는 데 사용할 수 있습니다. 큰 숫자로 버전. 를 사용 >>>0하면 0에서 0xFFFFFFFF 사이의 정수를 사용할 수 있습니다.

이 경우 ECMAScript는 32 비트 부호없는 정수로 배열 인덱스를 정의하기 때문에 유용합니다. 따라서 array.filterECMAScript Fifth Edition 표준의 내용을 정확하게 복제하는 방식 으로 구현하려는 경우 숫자를 32 비트 부호없는 int로 캐스트합니다.

(실제로는 거의 실제적인 필요성이 거기의 희망 사람들이 설정 될 수 없습니다 등 array.length으로 0.5, -1, 1e21또는 'LEMONS'.하지만 당신은 모르실 있도록이, 우리는 약을 얘기 자바 스크립트 저자는 ...)

요약:

1>>>0            === 1
-1>>>0           === 0xFFFFFFFF          -1>>0    === -1
1.7>>>0          === 1
0x100000002>>>0  === 2
1e21>>>0         === 0xDEA00000          1e21>>0  === -0x21600000
Infinity>>>0     === 0
NaN>>>0          === 0
null>>>0         === 0
'1'>>>0          === 1
'x'>>>0          === 0
Object>>>0       === 0

(* : 그것들은 플로트처럼 행동하는 것으로 정의되어 있습니다. 일부 JavaScript 엔진은 성능상의 이유로 가능할 때 실제로 int를 사용했다고해도 놀라지 않을 것입니다. 의 장점.)


2
심도 설명 및 테이블에서 +2, -1은 array.length가 자체적으로 유효성 검증하고 정수 또는 0이 아닌 다른 값으로 임의로 설정할 수 없기 때문에 (FF는이 오류를 발생시킵니다 :) RangeError: invalid array length.
저스틴 존슨

4
그러나이 사양은 의도적으로 많은 Array 함수가 비 Array (예 : via Array.prototype.filter.call)에서 호출 되도록 허용하므로 array실제로는 실제가 Array아닐 수도 있습니다. 다른 사용자 정의 클래스 일 수 있습니다. (안타깝게도, 그것은 호스트 객체이기 때문에 실제로 그렇게하고 싶을 때 NodeList가 될 수는 없습니다. arguments의사 배열 로 현실적으로 할 수있는 유일한 장소는 남겨 둡니다 .)
bobince

좋은 설명과 좋은 예! 불행히도 이것은 자바 스크립트의 또 다른 미친 측면입니다. 잘못된 유형을받을 때 오류가 발생하는 것에 대해 끔찍한 것이 무엇인지 이해하지 못합니다. 실수로 인한 실수로 형식 캐스팅을 만들지 않고도 동적 타이핑을 허용 할 수 있습니다. :(
Mike Williamson

">>> 0을 사용하면 0에서 0xFFFFFFFF 사이의 정수를 사용할 수 있습니다." if평가의 왼쪽이 정수가 아님을 식별하려고 할 때 진술의 내용은 무엇 입니까? 'lemons'>>>0 === 0 && 0 >>>0 === 0사실로 평가? 레몬은 분명히 한마디지만 ..?
Zze

58

부호없는 오른쪽 이동 연산자는 속성이 부호없는 32 비트 정수임 을 보장하기 위해 Mozilla 모든 배열 여분의 메소드 구현에 사용됩니다.length 됩니다.

length배열 객체 의 속성은 사양에서 다음과 같이 설명 됩니다.

모든 Array 객체에는 값이 항상 2 32 미만의 음이 아닌 정수인 length 속성이 있습니다.

이 연산자는 가장 짧은 방법이며 내부 배열 방법은 ToUint32 조작을 하지만 해당 메소드는 액세스 할 수 없으며 구현 목적으로 스펙에 존재합니다.

Mozilla 배열 엑스트라 구현은 ECMAScript 5를 준수 하려고 시도 합니다.Array.prototype.indexOf 방법 (§ 15.4.4.14)을보십시오.

1. O가 this 값을 전달하는 ToObject를 호출 한 결과로 둡니다. 
   논쟁으로.
2. lenValue가 O의 [[Get]] 내부 메소드를 호출 한 결과가되게하십시오. 
   "길이"인수
3. len하자  ToUint32 (lenValue)로 설정하십시오 .
....

보시다시피 ToUint32ES3 구현에서 ES5 사양을 준수하기 위해 메소드 의 동작을 재현하기를 원합니다. 앞에서 말했듯이 부호없는 오른쪽 시프트 연산자 가 가장 쉬운 방법입니다.


연결된 배열 엑스트라 구현은 정확하거나 정확할 수 있지만 코드는 여전히 잘못된 코드 예입니다. 아마도 의도를 명확히하는 의견조차도이 상황을 해결할 것입니다.
fmark

2
배열의 길이가 정수 가 아닐 수 있습니까? 나는 그것을 상상할 수 없다, 그래서 이런 종류의 ToUint32나에게는 약간 불필요 해 보인다.
Marcel Korpel 2016 년

7
@Marcel : 대부분의 Array.prototype메소드는 의도적으로 일반적 이라는 것을 명심하십시오 . 예를 들어, 배열과 같은 객체 에 사용될 수 있습니다 Array.prototype.indexOf.call({0:'foo', 1:'bar', length: 2}, 'bar') == 1;. arguments객체는 좋은 예입니다. 들어 순수 배열 객체는 유형 변경하는 것은 불가능 length그들이 특별한 구현하기 때문에, 속성을 [Put 할당이 이루어집니다] 내부 메서드 및 length속성을 다시 변환되어 ToUint32다른 조치는 위의 인덱스를 삭제 등, 촬영 새로운 길이 ...
CMS 1

32

이것이 부호없는 오른쪽 비트 시프트 연산자입니다. 이것과 부호있는 오른쪽 비트 시프트 연산자 의 차이점 은 부호없는 오른쪽 비트 시프트 연산자 ( >>> )가 왼쪽에서 0으로 채워지고 부호있는 오른쪽 비트 시프트 연산자 ( >> )가 부호 비트로 채워진다는 것입니다 이동할 때 숫자 값의 부호를 유지합니다.


이반, 그것은 0 자리만큼 이동합니다; 그 진술은 아무것도 변하지 않을 것입니다.
Dean J

3
@Ivan, 일반적으로 값을 0 자리로 이동하는 것은 절대 의미가 없다고 말하고 싶습니다. 그러나 이것은 Javascript이므로 그 뒤에 의미가있을 수 있습니다. 나는 자바 스크립트 전문가가 아니지만 값이 실제로 유형이없는 Javasacript 언어의 정수인지 확인하는 방법 일 수 있습니다.
driis

2
@Ivan, 아래 Justin의 답변을 참조하십시오. 실제로 len 변수에 숫자가 포함되도록하는 방법입니다.
driis

1
또한 >>>정수 +가 아닌 정수로 변환합니다 .
재귀

this.length >>> 0은 부호있는 정수를 부호없는 정수로 변환합니다. 개인적으로 서명되지 않은 정수가있는 이진 파일을로드 할 때 이것이 유용하다는 것을 알았습니다.
매트 파 킨스

29

디리스 는 운영자가 무엇이며 무엇을 하는지를 충분히 설명했습니다. 그 의미는 다음과 같습니다 / 사용 된 이유 :

원하는 방향을 이동하는 것은 0반환에게 원래의 번호를 수행하고 주조 할 것이다 null0. 당신이보고있는 예제 코드 가 숫자 인 경우에도 숫자 this.length >>> 0임을 확인하는 데 사용 하는 것 같습니다lenthis.length 는 정의되지 않은 .

많은 사람들에게 비트 단위 연산은 불분명합니다 (더글러스 크로포드 / jslint는 그러한 것들을 사용하지 말 것을 제안합니다). 그렇다는 것이 잘못되었다는 것을 의미하는 것은 아니지만 코드를 더 읽기 쉽게 만드는 더 유리하고 친숙한 방법이 있습니다. 그 보장하기 위해 더 명확한 방법 len이다는 0다음 두 가지 방법 중 하나입니다.

// Cast this.length to a number
var len = +this.length;

또는

// Cast this.length to a number, or use 0 if this.length is
// NaN/undefined (evaluates to false)
var len = +this.length || 0; 

1
, 두 번째 솔루션은 때때로 평가 것이지만 NaN.. 예 +{}... 그것은이 결합하는 것이 가장입니다+length||0
제임스

1
this.length는 배열 객체의 컨텍스트에 있으며 음수가 아닌 정수 (적어도 FF) 이외의 것은 될 수 없으므로 여기서는 가능하지 않습니다. 또한 {} || 1은 {}을 반환하므로 this.length가 객체이면 더 나아지지 않습니다. 첫 번째 방법으로 this.length를 단항 캐스트하면 이점은 this.length가 NaN 인 경우를 처리한다는 것입니다. 이를 반영하기 위해 응답을 수정했습니다.
저스틴 존슨

jslint는 var len = + this.length에 대해서도 "혼란 플러스"로 불평합니다. 더글러스, 너무 까다 롭다!
Bayard Randel

더글러스는 까다 롭습니다. 그의 주장은 현명하고 일반적으로 잘 확립되어 있지만, 절대적이거나 복음적인 것은 아닙니다.
저스틴 존슨

15

>>>는 IS 부호 오른쪽 시프트 연산자 ( 페이지. 자바 스크립트 1.5 사양의 76 )에 반대로 >>상기 서명 오른쪽 시프트 연산자.

>>>음수를 이동 하면 부호 비트가 유지되지 않으므로 음수를 이동 한 결과가 변경 됩니다 . 이것의 결과는 예를 들어 해석기에서 이해할 수 있습니다.

$ 1 >> 0
1
$ 0 >> 0
0
$ -1 >> 0
-1
$ 1 >>> 0
1
$ 0 >>> 0
0
$ -1 >>> 0
4294967295
$(-1 >>> 0).toString(16)
"ffffffff"
$ "cabbage" >>> 0
0

따라서 여기서 수행하려는 것은 길이를 가져 오거나 "cabbage"위 의 예에 따라 길이가 정의되지 않았거나 정수가 아닌 경우 0을 얻는 것 입니다. 나는이 경우 this.length결코 없을 것이라고 가정하는 것이 안전하다고 생각 한다 < 0. 그럼에도 불구하고, 나는 이 예제가 두 가지 이유로 불쾌한 핵 이라고 주장합니다 .

  1. <<<음수 를 사용할 때 의 동작으로 , 위의 예에서 부작용이 발생하지 않았을 수 있습니다.

  2. 이 질문의 존재가 확인하기 때문에 코드의 의도는 분명하지 않습니다 .

모범 사례는 성능이 절대적으로 중요하지 않은 한 더 읽기 쉬운 것을 사용하는 것입니다.

isNaN(parseInt(foo)) ? 0 : parseInt(foo)

Sooo ... @johncatfish이 맞습니까? this.length가 음이 아닌지 확인하는 것입니까?
Anthony

4
-1 >>> 0언제라도 일어날 수 있습니까? 그렇다면 4294967295로 바꾸는 것이 정말 바람직합니까? 이로 인해 루프가 필요한 것보다 몇 번 더 실행될 수 있습니다.
deceze

@deceze : 구현을 보지 않으면 this.length알 수 없습니다. "sane"구현의 경우 문자열 길이는 음수가 아니어야하지만 "sane"환경에서는 this.length항상 정수를 반환하는 속성이 있다고 가정 할 수 있습니다 .
fmark

>>>는 부호 비트를 보존하지 않습니다 .. 좋아 .. 그래서, 우리가 음수를 다룰 때 물어봐야합니다. 형식이거나 부호있는 정수 형식입니까? 어떻게 알 수 있습니까? 그런데, 2 초는 서명 표기법에 대한 대안이다 .. 나는 부호 비트가 있다고하지 아마 생각 보완하지만, 정수의 부호 결정하는 것이 가능하다
barlop

10

두 가지 이유 :

  1. >>>의 결과는 "통합"입니다

  2. undefined >>> 0 = 0 (JS가 LFS를 숫자 컨텍스트로 강제 변환하려고 시도하기 때문에 "foo"에서 작동합니다. >>> 0 등)

JS의 숫자는 내부 표현이 double이라는 것을 기억하십시오. 그것은 길이에 대한 기본적인 입력 상태의 "빠른"방법입니다.

그러나 -1 >>> 0 (원하는 길이가 아닐 수도 있습니다!)


0

아래 샘플 Java 코드가 잘 설명되어 있습니다.

int x = 64;

System.out.println("x >>> 3 = "  + (x >>> 3));
System.out.println("x >> 3 = "  + (x >> 3));
System.out.println(Integer.toBinaryString(x >>> 3));
System.out.println(Integer.toBinaryString(x >> 3));

출력은 다음과 같습니다.

x >>> 3 = 536870904
x >> 3 = -8
11111111111111111111111111000
11111111111111111111111111111000
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.