📢 어렵고 정석적인 개념 설명보다는 저같은 초보자도 이해하기 쉽게 정리하는 것을 원칙으로 포스팅하고 있습니다. 😄

[JavaScript] [] == ![]은 왜 true가 나오는걸까?

우리가 알고 있던 것과 다른 개념

[] == ![] // true

자바스크립트를 조금 끄적여본 사람이라면 머릿속에 쌓아온 자바스크립트적 통념이란 게 있다.

1 == !1의 결과로 false가 나온다는 것이 바로 그 통념의 예시이다. 이것은 굳이 코딩을 모르는 사람이 봐도 비교 연산자만 알고 있다면 답을 알 수 있는 기본적인 상식이기도 하다.

 

이런 통념을 바탕으로 [] == ![]을 보면 어떨까? 처음엔 '배열과 배열이 아닌 게 같다고? 당연히 false겠네'라고 생각할 것이다. 하지만, 이것은 true를 리턴한다. 이때부터 우리는 그동안 쌓아왔던 통념과 충돌을 느끼고 내가 그동안 잘못 배운 건가라는 생각에 사로 잡히게 된다. 왜 이런 결과가 나오는지에 대해서는 동등 연산자(==)와 배열의 타입에 대해서 공부해 보면 알 수 있다.

 

빈 배열이 동등 연산자(==)를 만났을 때

'1' == 1 // true
0 == false // true
[] == false // true

'1'과 1은 서로 타입은 다르지만 값은 같기 때문에 true가 나온다. 0 또한 falsy한 값이기 때문에 true가 나온다.

이처럼 == 연산자는 숫자와 문자를 비교할 땐 서로 타입이 달라도 값만 같으면 true를 리턴하며, 0과 Boolean 값과 비교할 때는 서로 생김새가 달라도 truthy한 지 falsy한 지를 서로 비교하여 Boolean 값을 리턴한다.

 

[] == ![]가 true인지에 대해서 알기 위해서는 첫 번째로 빈 배열이 truthy한 지 falsy한 지를 알아야 한다.

정답부터 말하면 빈 배열은 truthy한 속성을 갖고 있다. 따라서, ![]의 값은 !true와 같기 때문에 false가 된다.

그럼 여기서 한 가지 의문이 들 것이다. []가 true라고 했다면, [] == ![]는 true == false와 같으니까 false가 나와야 하지 않을까 하는 의문이다. 

 

동등 연산자에는 '타입 강제 변환 규칙'이라는 게 있다. A == B라는 비교식이 있을 때, 동등 연산자는 A와 B를 비교하기 위해 원래 가지고 있던 A와 B의 타입을 강제로 변환시킨다. 이러한 규칙으로 인해 빈 배열은 빈 문자열로 변하고, 빈 문자열은 숫자 0으로 변환된다. 즉, [] == ![] 에서의 []은 형 변환으로 인해 false가 돼버리며 결과적으로 false == false가 돼서 true를 반환하는 것이다.

✔️ [] == ![]가 true인 논리를 정리해보자!
1. 오른쪽 ![]은 !true이므로 false이다. (배열은 true이기 때문)
2. 왼쪽 []은 == 연산자로 인해 형 변환이 발생하여 숫자 0이 되고, 이것은 false가 된다.
3. 배열은 true가 맞다. 따라서 오른쪽 ![]이 false가 나오는 것이다.
4. 왼쪽 []혼자 있으면 true이다. 하지만 == 연산자를 만나서 0으로 변환되어 false가 돼버렸다.

 

배열과 배열끼리는 비교할 수 없다?

[] !== [] // true
[1, 2] === [1, 2] // false

번외로, 배열과 배열을 비교할 때도 주의할 사항이 있다.

1 === 1은 true이며, 's' === 's'도 true이다. 하지만, [1, 2] === [1, 2]는 false이다. 왜 그럴까?

정답부터 말하면, 배열은 원시값이 아니라 참조값이기 때문이다. 그렇다면 원시값은 뭐고 참조값은 뭘까?

 

우리가 변수에 데이터를 저장할 때 2가지 타입으로 저장할 수 있는데, 바로 원시타입과 참조타입이다.

원시타입은 변수에 저장된 실제값에 직접적으로 접근할 수 있는 속성을 가지며 Number, String, Boolean, Null, Undefined 등 대부분의 타입들이 원시타입이다. 쉽게 얘기하면 변수를 직접적으로 가져다가 쓸 수 있냐의 질문에 '네'라고 대답할 수 있는 타입인 것이다.

 

참조타입은 메모리에 저장된 객체 타입이며, 메모리에 직접적으로 접근할 수 없기 때문에 변수에는 데이터에 대한 참조만이 저장된다. Array, Object, Function이 그 예시이다. 

 

다시 배열 이야기로 돌아오자면, 배열은 원시타입이기 때문에 변수가 그 값에 직접적으로 접근할 수가 없다.

따라서, [1, 2]와 [1, 2]가 있을 때 둘은 그냥 배열이라는 타입이 같을 뿐이지 같은 값이 아닌 것이다.

그렇기 때문에 [1, 2] === [1, 2]의 값으로 false가 리턴되는 것이다. 즉, 똑같이 창문 있는 집이라고 모두 202호는 아닌 것처럼 말이다.

 

1. [] == ![] ☞ [] == fasle ☞ ''(빈 문자열) == false ☞ 0 == false
2. []은 원래 truthy한 속성. 하지만 ==를 만나면 타입 강제 변환 규칙으로 인해 0이 돼버림
3. 배열은 참조 타입이기 때문에 '배열 == 배열'은 모두 false가 나옴. 같은 배열은 존재하지 않음.