JavaScript에서 왜 2 == [2]입니까?


164

최근 2 == [2]에 JavaScript에서 발견했습니다 . 이 기발한 결과는 몇 가지 흥미로운 결과를 낳습니다.

var a = [0, 1, 2, 3];
a[[2]] === a[2]; // this is true

마찬가지로 다음과 같이 작동합니다.

var a = { "abc" : 1 };
a[["abc"]] === a["abc"]; // this is also true

여전히 낯선 사람이라도, 이것은 잘 작동합니다.

[[[[[[[2]]]]]]] == 2; // this is true too! WTF?

이러한 동작은 모든 브라우저에서 일관된 것처럼 보입니다.

이것이 왜 언어 기능인지 아십니까?

이 "기능"의 결과는 다음과 같습니다.

[0] == false // true
if ([0]) { /* executes */ } // [0] is both true and false!

var a = [0];
a == a // true
a == !a // also true, WTF?

이러한 예는 jimbojw에 의해 발견되었다 http://jimbojw.com 명성뿐만 아니라 walkingeyerobot .

답변:


134

ECMA 사양 (문제에 대한 ECMA-262, 3 판 : 11.9.3, 9.1, 8.6.2.6의 관련 섹션)에서 비교 알고리즘을 찾을 수 있습니다.

관련된 추상 알고리즘을 JS로 다시 변환하면 평가할 때 2 == [2]기본적으로 다음과 같은 결과 가 발생 합니다.

2 === Number([2].valueOf().toString())

여기서 valueOf()for 배열은 배열 자체를 반환하고 단일 요소 배열의 문자열 표현은 단일 요소의 문자열 표현입니다.

이것은 또한 [[[[[[[2]]]]]]].toString()여전히 문자열 인 세 번째 예를 설명 합니다 2.

보시다시피, 많은 배후의 마술이 관련되어 있기 때문에 일반적으로 엄격한 항등 연산자 만 사용합니다 ===.

속성 이름은 항상 문자열이므로 첫 번째와 두 번째 예는 따르기가 더 쉽습니다.

a[[2]]

에 해당

a[[2].toString()]

그냥

a["2"]

배열 키가 발생하기 전에 숫자 키도 속성 이름 (예 : 문자열)으로 처리됩니다.


10

==연산자 의 암시 적 유형 변환 때문입니다 .

[2]는 숫자와 비교할 때 숫자는 2로 변환됩니다. +[2] 에서 단항 연산자를 사용해보십시오 .

> +[2]
2

다른 사람들은 [2]가 문자열로 변환된다고 말합니다. +"2"또한 숫자 2입니다
dlamblin

1
실제로는 쉽지 않습니다. [2]는 더 가까운 문자열로 변환되지만 ecma-international.org/ecma-262/5.1/#sec-11.9.3
neo

10
var a = [0, 1, 2, 3];
a[[2]] === a[2]; // this is true

방정식의 오른쪽에는 a [2]가 있는데,이 값은 값 2를 갖는 숫자 유형을 반환합니다. 왼쪽에서 먼저 단일 객체가 2 인 새 배열을 만듭니다. 그런 다음 a [( 배열은 여기에 있습니다)]. 이것이 문자열 또는 숫자로 평가되는지 확실하지 않습니다. 2 또는 "2". 먼저 문자열을 살펴 보겠습니다. 나는 a [ "2"]가 새로운 변수를 만들고 null을 리턴 할 것이라고 믿는다. null! == 2. 따라서 실제로 암시 적으로 숫자로 변환한다고 가정합니다. a [2]는 유형 (따라서 === 작동)과 값에서 2와 2의 일치를 반환합니다. a [value]는 문자열이나 숫자를 기대하기 때문에 배열을 숫자로 암시 적으로 변환한다고 생각합니다. 숫자가 우선 순위가 높은 것 같습니다.

참고로, 누가 그 우선 순위를 결정하는지 궁금합니다. [2]에 첫 번째 항목 인 숫자가 있기 때문에 숫자로 변환됩니까? 또는 배열을 배열에 전달할 때 배열을 먼저 숫자로 변환 한 다음 문자열로 변환하려고 시도합니다. 누가 알아?

var a = { "abc" : 1 };
a[["abc"]] === a["abc"];

이 예에서는 abc라는 멤버를 사용하여 a라는 객체를 만듭니다. 방정식의 오른쪽은 매우 간단합니다. a.abc와 같습니다. 왼쪽이 먼저 [ "abc"]의 리터럴 배열을 만듭니다. 그런 다음 새로 생성 된 배열을 전달하여 객체에서 변수를 검색합니다. 이것은 문자열을 기대하기 때문에 배열을 문자열로 변환합니다. 이제는 1과 동일한 a [ "abc"]로 평가됩니다. 1과 1은 같은 유형 (이는 ===가 작동하는 이유)과 동일한 값입니다.

[[[[[[[2]]]]]]] == 2; 

이것은 단지 암묵적인 변환입니다. 유형이 일치하지 않기 때문에이 상황에서는 === 작동하지 않습니다.


우선 순위에 대한 귀하의 질문에 대한 답변 : 배열에 ==적용 ToPrimitive()됩니다.이 배열은 toString()메소드 를 호출 하므로 실제로 비교 2하는 것은 문자열 의 숫자입니다 "2". 문자열과 숫자의 비교는 문자열을 변환하여 이루어집니다
Christoph

8

==경우 Doug Crockford 는 항상을 사용하는 것이 좋습니다 ===. 암시 적 유형 변환을 수행하지 않습니다.

의 예에서는 ===등식 연산자가 호출되기 전에 암시 적 형식 변환이 수행됩니다.


7
[0] == false // true
if ([0]) { /* executes */ } // [0] is both true and false!

흥미 롭습니다. 실제로 [0]이 참인지 거짓인지는 아닙니다. 실제로

[0] == true // false

if () 연산자를 처리하는 자바 스크립트의 재미있는 방법입니다.


4
실제로, 그것은 재미있는 방법입니다 ==; 실제 명시 적 캐스트 (예 : Boolean([0])또는 !![0]) 를 사용하는 경우 다음 과 같이 부울 컨텍스트에서 [0]평가됩니다 true. JS에서는 모든 객체가 고려됩니다true
Christoph

6

한 항목의 배열은 항목 자체로 취급 될 수 있습니다.

이것은 오리 타이핑 때문입니다. "2"== 2 == [2] 이후 가능합니다.


4
형식이 일치하지 않기 때문입니다. 첫 번째 예에서는 왼쪽이 먼저 평가되고 유형이 일치합니다.
Shawn

8
또한 오리 타이핑이 올바른 단어라고 생각하지 않습니다. ==비교하기 전에 연산자가 수행하는 암시 적 유형 변환 과 관련이 있습니다.
체탄 S

14
이것은 오리 타이핑과는 관련이없고 약한 타이핑, 즉 암시 적 타입 변환과 관련이 있습니다
Christoph

@Chetan : 그가 말한 것;)
Christoph

2
Chetan과 Christoph가 말한 것.
Tim Down

3

다른 답변에 약간의 세부 사항을 추가하려면 ...을 비교할 때 ArrayA를Number , 자바 스크립트가 변환됩니다 Array함께 parseFloat(array). 콘솔 (예 : Firebug 또는 Web Inspector)에서 직접 시도하여 다른 Array값으로 변환되는 것을 확인할 수 있습니다.

parseFloat([2]); // 2
parseFloat([2, 3]); // 2
parseFloat(['', 2]); // NaN

들면 ArrayS, parseFloat온 동작을 수행Array 최초 부재 파기 나머지.

편집 : Christoph의 세부 사항에 따르면 내부에서 더 긴 형식을 사용하고 있지만 결과는 일관되게 동일 parseFloat하므로 언제든지 사용할 수 있습니다parseFloat(array) 속기로 하여 변환 방법을 알 수 있습니다.


2

모든 경우에 2 개의 객체를 비교하고 있습니다. ==를 사용하지 마십시오. 비교를 생각하고 있다면 ==가 아니라 ===를 염두에두고있는 것입니다. == 종종 미친 효과를 줄 수 있습니다. 언어에서 좋은 부분을 찾으십시오. :)


0

편집 설명질문 섹션에 :

제 1 예

[0] == false // true
if ([0]) { /* executes */ } // [0] is both true and false!

위의 Christoph의 답변에 따라 첫 번째 유형 캐스트 ​​[0]을 기본 값으로 "0"( [0].valueOf().toString())

"0" == false

이제 Boolean (false)을 Number로 형변환하고 String ( "0")을 Number로 형변환하십시오.

Number("0") == Number(false)
or  0 == 0 
so, [0] == false  // true

if진술에 관해서 는, if 조건 자체에 명시적인 비교가 없다면, 조건은 진실한 값을 합니다.

단지가 있습니다 6 falsy 값은 : 거짓, 널 (null), 정의되지 않은, 0, NaN가 빈 문자열 "". 그리고 잘못된 가치가 아닌 것은 진실한 가치입니다.

[0]은 잘못된 값이 아니기 때문에 정확한 값이므로 if명령문이 true로 평가되고 명령문을 실행합니다.


두 번째 예

var a = [0];
a == a // true
a == !a // also true, WTF?

다시 기본 값을 입력하십시오.

    a = a
or  [0].valueOf().toString() == [0].valueOf().toString()
or  "0" == "0" // true; same type, same value


a == !a
or  [0].valueOf().toString() == [0].valueOf().toString()
or  "0" == !"0"
or  "0" == false
or  Number("0") == Number(false)
or  0 = 0   // true
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.