Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

민규의 개발블로그

자바스크립트 강제변환-2 본문

Javascript

자바스크립트 강제변환-2

규몽 2020. 11. 17. 17:11

 


 

암시적 변환

 

암시적 강제변환은 부수 효과가 명황하지 않게 숨겨진 형태로 일어나는 타입변환이다.

명시적 강제변환의 목적(코드를 명확하게, 이해할 수 있게 작성함)과는 반대라는 사실에 유해하다는 인식이 있지만

"You Don't know JS" 책에서는 다른 관점에서 설명한다.

 

이 책에서는 암시적 강제변환은 많은 장점이 있지만 몇 가지 단점 때문에 무조건 나쁘다라고 단정하진 말자는 주의다.

암시적 강제변환으로 지저분한 코드를 감추고 코딩에 도움이 될 수 있다.

 

문자열 <--> 숫자 

 

처음 알게 된 배열 덧셈

 

간단히 말하면 + 연산의 한쪽 피연산자가 문자열이면(어떤 과정을 거쳐 문자열이 되면) +는 문자열 붙이기 연산을 한다.

피연산자중 하나가 객체라면, 먼저 이 값에 ToPrimitive 추상 연산을 수행하고, 다시 ToPrimitive는 number 콘텍스트 힌트를 넘겨 [[DefaultValue]] 알고리즘을 호출한다.

그래서 valueOf( )에 배열을 넘기면 단순 원시 값을 반환할 수 없으므로 바통은 toString( )으로 넘어가서 두 배열은 각각 "1,2"와 "3,4"가 되고 +는 두 문자열을 붙여 최종 "1,23,4"가 된다.

 

 

멋진 사례

 

a+"" 는 숫자를 문자열로 강제변환하는 흔한 관용 코드다.

명시적 강제변환 String(a)에 비해 암시적 강제변환 a+"" 가 더 깔끔해 보이지 않는가?? -- 개인적인 생각

 

 

유의 할 점은 추상 연산 과정에서 a + ""는 a 값을 valueOf( ) 메서드에 전달하여 호출하고, 그 결괏값을 추상 연산 하여 최종적인 문자열로 변환된다. 그러나 String(a)는 toString( )를 직접 호출할 뿐이다.

따라서 객체라면 결괏값이 달라질 수 있다.

 

 

 

암시적 강제변환 -> 불리언

 

불리언으로 암시적인 강제변환이 일어나는 표현식

 

  • if ( )문의 조건 표현식
  • for(  ;  ;  )에서 두 번째 저간 펴햔ㅅ;ㄱ
  • while ( )및 do while( ) 루프의 조건 표현식
  • ?  : 삼항 연산 시 첫 번째 조건 표현식
  • || 및 &&의 좌측 피연산자

 

&&와 || 연산자

 

자바스크립트에서는 이것들을 '논리 연산자'라는 명칭보단 정확하게는 '피연산자 선택 연산자'라 볼 수도 있다.

이유는 자바스크립트에서 이 두 연산자는 다른 언어와 달리 실제로 결괏값이 논리 값이 아니기 때문이다.

결괏값은 두 피연산자 중 한쪽값이다. 즉 두 피연산자의 값들 중 하나다.

 

 

 

||, && 연산자는 우선 첫 번째 피연산자의 불리언 값을 평가한다. 피연산자가 비 불리언 타입이면 먼저 ToBoolean으로 강제변환 후 평가를 계속한다.

 

|| 연산자는 그 결과가 true면 첫 번째 피연산자 값을, false면 두 번째 피연산자값을 반환한다.

&& 연산자는 true면 두 번째 피연산자 값을, false면 첫 번째 피연산자 값을 반환한다.

 

따라서 if문이나 for루프는 이 결괏값들을 불리언으로 암시적 강제변환하여 돌아간다.

 

 

느슨한//엄격한 동등비교

 

느슨한 동등 비교는 == 연산자를, 엄격한 동등 비교는 === 연산자를 각각 사용한다.

결론 부터 말하면 동등함의 비교 시 ==는 강제변환을 허용하지만, ===는 강제변환을 허용하지 않는다.

 

 

a === b는 강제변환이 허용되지 않는 데다 10과 "10"은 누가봐도 다른 값이라 false다.

하지만 느슨한 동등 비교 a == b에서는 피연산자의 타입이 다르면, 비교 알고리즘에 의한 한쪽 또는 양쪽 피연산자 값이 알아서 암시적으로 변환된다.

 

  • Type(x)가 Number고 Type(y)가 String이면, x == ToNumber(y) 비교 결과를 반환한다.
  • Type(x)가 String이고 Type(y)가 Number이면, ToNumber(x) == y 비교 결과를 반환한다.

불리언에서 실수 하는 것이 있다. 

 

  • Type(x)가 불리언이면 ToNumber(x) == y의 비교 결과를 반환한다.
  • Type(y)가 불리언이면 x == ToNumber(y)의 비교 결과를 반환한다.

 

위의 코드에서 b를 ToNumber 강제 변환하면 1이다. 따라서 a와는 같고 c와는 다르다.

 

null과 undefined는 느슨한 동등 비교하면 서로에게 타입을 맞춘다.

 

 

 

null <--> undefined 강제변환은 안전하고 예측 가능하며, 다른 값도 비교 결과 긍정 오류를 할 가능성이 없다.

따라서 아래의 강제변환은 권장한다.

a == null의 평가 결과는 Something( )이 null이나 undefined를 반환할 경우에만 true, 이외의 값(0,false, "" 등도 포함)이 반환되면 false다.

 

 

객체의 경우는 다음과 같다.

 

  • Type(x)가 String 또는 Number고 Type(y)가 객체라면, x == ToPrimitive(y)의 비교 결과를 반환한다.
  • Type(x)가 객체이고 Type(y)가 String 또는 Number라면, ToPrimitive(x) == y의 비교 결과를 반환한다. 

원시 값을 감싼 객체 래퍼를 언박싱하여 비교한다. 그러나 undefined, null은 객체 래퍼가 따로 없으므로, NaN은 Number로 박싱되지만 ==를 만나 언박싱되면 결국 NaN == NaN이 되어 false라 예외다.

 


아래 표를 보면 Falsy 값 비교에 관한 희귀 사례 목록이다.

따라서 강제변환의 안전한 사용법은

 

  • 피연산자 중 하나가 true/false일 가능성이 있으면 절대로 == 연산자를 쓰지 않는다.
  • 피연산자 중 하나가 [ ], " ", 0이 될 가능성이 있으면 가급적 == 연산자를 쓰지 않는다.

두가지 원칙을 준수하며 강제변환의 함정들을 피해가면 좀 더 코드를 간결하게 할 수 있고 골치 아픈 디버깅의 늪에서 나오는데 도움이 된다.

 

 

 

추상 관계 비교

 

추상적 관계 비교 알고리즘은 비교 시 피연산자 모두 문자열일 때와 그 외의 경우, 두 가지로 나뉜다.

 

먼저 두 피연산자에 대해 ToPrimitive 강제변환을 실시하고, 어느 한쪽이라도 문자열이 아닐 경우 양쪽 모두 ToNumber로 강제 변환하여 비교한다.

b < c 가 false인 이유는 비교 대상이 모두 문자열 값이면, 각 문자를 단순 어휘 비교한다. 따라서 "0"은 어휘상 "1"보다 작은 값이므로 실패한다.

 

 

 

명시적 강제변환은 다른 타입의 값으로 변환하는 의도가 확실한 코드를 말하며 혼동의 여지를 줄이고 코드 가독성 및 유지 보수성을 높일 수 있는 장점이 있다.

 

암시적 강제변환은 숨겨진 로직에 의한 부수 효과가 있으며 타입변환이 처리되는 과정이 명확하지 않다.

암시적 강제변환은 변환 과정이 구체적으로 어떻게 일어나는지 명확하게 알고 사용하면 부수 효과를 누릴 수 있을 것 이다.

'Javascript' 카테고리의 다른 글

자바스크립트 스코프  (0) 2020.11.20
자바스크립트 문법  (0) 2020.11.19
자바스크립트 강제변환-1  (0) 2020.11.16
자바스크립트 네이티브  (0) 2020.11.13
자바스크립트 값  (0) 2020.11.12
Comments