목차
- 값 변환
- 추상 연산
- 명시적 강제변환
- 암시적 변환
- 느슨한/엄격한 동등 비교
- 추상 관계 비교
1. 값 변환
타입 캐스팅 | 강제 변환 | |
구분 | 어떤 값의 타입을 바꾸는 과정이 명시적이면 타입 캐스팅이다. (정적타입 언어에서 컴파일시점에 발생) |
어떤 값의 타입을 바꾸는 과정이 암시적이면 강제 변환이다. (동적타입 언어에서 런타임시점에 발생) |
명시적 강제변환 : 코드에서 의도적으로 타입 변환을 일으키는 것이 명백
const a = 42;
const b = String(a); // 명시적 "42"
암시적 강제변환 : 다른 작업 도중 불분명한 부수효과로 부터 발생한 타입 변환
2. 추상 연산
-ToString
문자열이 아닌 값 → 문자열 변환은 ToString 추상 연산 로직이 담당한다.
- 내장 원시 값은 본연의 문자열화 방법이 정해져 있다. 숫자는 문자열로 바뀌지만 큰 수는 지수 형태로 바뀐다.
- 일반 객체는 지정하지 않으면 기본적으로 toString() 메서드가 [[class]]를 반환한다.
- 자신의 toString() 메서드를 가진 객체는 문자열 처럼 사용하면 이 메서드가 기본 호출되어 toString()을 대체한다.
- 배열은 기본적으로 재정의된 toString()이 있다. 문자열 변환 시 모든 원소 값이 콤마(,)로 분리된 형태로 이어진다.
- toString() 메서드는 명시적으로 호출 가능, 문자열 콘텍스트에서 비문자열 값이 있는 경우에도 자동 호출된다.
JSON 문자열화
JSON.stringify()를 이용해 JSON안전값을 문자열화 할 수 있다.
JSON 안전값이 아니면 모두 다른 언어로 인식하여 JSON값으로 쓸 수 없는 표준 JSON 규격을 벗어난 값이다.
toString()과 기본적으로 같은 로직이다.
JSON.stringify()의 인자에 따른 결과
// JSON 안전값
JSON.stringify( 42 ); // "42" 숫자, 문자열, null, boolean 값은 안전값으로 사용
JSON.stringify( undefined ); // undefined
JSON.stringify( function(){} ); // undefined
JSON.stringify(
[ 1, undefined, function(){} ]
); // "[ 1, null, null, 4 ]"
JSON.stringify(
{ a: 2, b: function(){} }
); // "{ "a": 2 }"
인자가 undefined, 함수, 심벌 값이면 자동으로 누락시키며 만약 배열에 포함되어 있으면 null로 바꾼다.
객체 프로퍼티에 있다면 간단하게 지워버린다.
부적절한 JSON값이나 직렬화하기 곤란한 객체 값을 문자열화 하려면 toJSON()메서드를 따로 정의해야한다.
const o = {};
const a = {
b: 42,
c: o,
d: function(){}
}
// 'a'를 환형 참조 객체로 만든다.
o.e = a;
// 환형 참조 객체는 JSON문자열화 시 에러가 발생
// JSON.stringify( a );
// JSON 값으로 직렬화 하는 함수를 선언
a.toJSON = function(){
// 직렬화에 프로퍼티 'b'만 포함시킨다.
return { b: this.b }
};
JSON.stringify( a ); // "{"b": 42}"
toJSON은 어떤 타입이든 적절히 평범한 실제 값을 반환한다.
→ toJSON의 역활은 "문자열 화기 적절한 JSON 안전값으로 바꾸는 것" 이다.
JSON.stringify()의 유용한 기능 두번째 인자 대체자 Replacer
Replacer가 배열 혹은 함수형인 두번째 인자를 지정하여 객체를 재귀적으로 직렬화 하며 필터링 가능
1) Replacer가 배열이면 전체 원소는 문자열이어야 하고 각 원소는 객체 직렬화의 대상 프로퍼티명이다.
(여기서 포함되지 않은 프로퍼티는 직렬화 과정에서 빠진다.)
2) Replacer가 함수면 처음 한 번은 객체 자신에 대해, 그 다음엔 각 객체 프로퍼티별로 한 번씩 실행하며
매번 키와 값 두 인자를 전달한다. 직렬화 과정에서 해당 키를 건너뛰려면 undefined를, 그 외엔 해당 값을 반환한다.
const a = {
b: 42,
c: "42",
d: [1,2,3]
};
JSON.stringify(a, ["b", "c"]); // "{ "b": 42, "c": "42" }"
JSON.stringify(a, function(k,v){
if(k !== "c") return v;
} );
// "{ "b": 42, "d": [1,2,3] }"
JSON.stringify()의 유용한 기능 세번째 인자 Space
읽기 쉽게 들여쓰기 할 빈공간의 개수를 지정 혹은 문자열(10자 까지 가능)을 지정한다.
1) 문자열, 숫자, 불리언, null 값이 JSON으로 문자열화 하는 방식은 toString 추상연산의 규칙에
따라 문자열 값으로 강제변환되는 방식과 동일하다.
2) JSON.stringify()에 전달한 객체가 자체 toJSON() 메서드를 갖고 있다면, 문자열화 전 toJSON()가
자동 호출되어 JSON 안전값으로 강제 변환된다.
const a = {
b: 42,
c: "42",
d: [1,2,3]
};
JSON.stringify( a, null, 3 );
// "{ "b": 42, "c": "42", "d": [1, 2, 3] }"
JSON.stringify( a, null, "----" );
// "{ ----"b": 42, ----"c": "42",
// ----"d": [--------1, --------2, --------3]---- }"
JSON.stringify()은 직접적인 강제 변환의 형식은 아니지만 두 가지로 이유로 ToString 갖에 변환과 연관된다.
-ToNumber
숫자가 아닌 값 → 수식연산이 가능한 숫자 변환 로직
객체(배열 포함)는 일단 원시값으로 변환 후 그 결과값(아직 숫자가 아닌 원시값)을
앞서 설명한 ToNumber 규칙에 의해 강제변환한다.
동등한 원시값으로 바꾸기 위해 ToPrimitive 추상연산 과정에서 해당 객체가 valueOf() 메서드를 구현했는지 확인한다.
→ valueOf() 사용가능 하고 원시값이 반환되면 그대로 강제변환된다.
그렇지 않다면 toString()을 이용해 강제변환한다.
ES5부터 [[Prototype]]가 null인 경우 대부분 object.create(null)을 이용해
강제변경이 불가능한 객체( valueOf(), toString()이 없는 )를 만들 수 있다.
-ToBoolean
JS에서는 숫자는 숫자고, 불리언은 불리언이다.
1은 true로, 0은 false로 강제변환이 가능하지만 별개의 값이다.
Falsy 값
자바스크립트의 모든 값은 둘중 하나이다.
1) 불리언으로 강제변환하면 false가 되는 값
2) 1번을 제외한 나머지(명백한 true값)
인자타입 | 결과 값 | falsy 값 - undefined - null - false - ±0, NaN - " " |
Undefined | false | |
Null | false | |
Boolean | 인자값과 동일(변환X) | |
Number | 인자가 ±0 혹은 NaN이면 false, 그 외엔 true | |
String | 인자가 공백이면 (length가 0) false, 그 외에는 true | |
Object | true |
Falsy 객체
const a = new Boolean(false);
const b = new Number(0);
const c = new String(" ");
// const d = Boolean(a && b && c); //true
// Boolean이 없으면 빈 문자열이 출력된다.
위의 예시는 Falsy객체가 아니다.
falsy객체는 브라우저 만의 특이한 작동 방식을 가지 값이다.
falsy 객체는 겉보기엔 평범한 객체처럼 작동할 것 같지만 불리언으로 강제 변경하면 false이다.
→유사배열(객체).document.all에서 .document.all는웹페이지의 요소를 자바스크립트 프로그램에서 가져올 수 있게 함
Truthy 값
falsy 값 목록에 없는 모든 값 (Object는 비어있어도 truthy)
truthy/falsy 개념은 어떤 값을 불리언 타입으로 (명시적/암시적) 강제변환시
해당 값의 작동 방식을 이해한다는 점이 중요하다.
3. 명시적 강제변환 : 분명하고 확실한 타입 변환
- 문자열 ⇄ 숫자
String()과 Number() 함수를 이용한다.
앞에 new가 붙지 않아 객체 래퍼를 생성하지 않는다.
const a = 42;
const b = String(a); // "42"
const c = "3.14";
const d = Number(c); // 3.14
String()은 ToString 추상 연산 로직에 따라 값을 원시 로직값으로 강제 변환한다.
Number() 역시 ToNumber 추상 연산 로직에 따라 값을 받아 숫자값으로 강제 변환한다.
const a = 42;
const b = a.toString(); // "42"
const c = "3.14";
const d = +c; // 3.14
a.toString() 호출은 암시적인 요소가 감춰진 "명시적으로 암시적인 작동"이다.
→
원시값 42는 toString() 메서드가 없기에 엔진이 toString을 사용할 수 있게 자동으로 객체래퍼로 박싱한다.
날짜 → 숫자
+단항 연산자는 "Date객체 → 숫자" 강제변환 용도로 쓰인다.
결과값이 날짜/시간 값을 유닉스 타임스탬프 표현형이기 때문이다.
ES5 이후에는 정적 함수 Date.now()를 사용하자.
if(!Date.now){
Date.now = function(){
return +new Date();
};
}
현재 타임스탬프는 Date.now()로, 그 외 특정 날짜/시간의 타임스템프는 new Date().getTime()을 대신 사용하자.
이상한 나라의 틸드(~) : 0과 1을 모두 뒤집는 Bitwise Not 연산자
~(틸드)는 종종 사람들이 간과하는 자바스크립트의 강제변환 연산자이다.
동작 : 32비트 숫자로 강제변환한 후 NOT연산을 한다.
~x는 -(x+1)과 대략 비슷하다.
~42; // -( 42 + 1 ) ==> -43
return >=0은 성공, return -1은 실패라는 의미를 부여한다.
→ -(x+1)을 0으로 만드는 유일값은 -1이다. -1과 같은 성질의 값을 경계값이라 한다.
✅경계값 : 동일 타입의 더 확장된 값의 집합내에서 임의의 의미를 부여한 값
문자열 메서드 indexOf()를 정의시 문자열 검색에서 찾으면 0부터 시작하는 숫자값(index), 못찾으면 -1을 반환한다.
indexOf()에 ~를 붙이면 강제변환하여 불리언 값으로 적절히 만들 수 있다.
const a = "Hello World"
~a.indexOf( "lo" ); // -4 <--truthy
if(~a.indexOf( "lo" )){ //true
//찾음
}
~a.indexOf( "ol" ); // 0 <--falsy
!~a.indexOf( "ol" ); //true
if(!~a.indexOf("ol")){ //true
//못 찾음
}
~은 indexOf()로 검색결과 실패시 -1을 falsy한 0으로, 그 외는 truthy한 값으로 바꾼다.
비트 잘라내기
~를 이용해 ~~처럼 두번 작성하여 숫자의 소숫점 이상 부분을 잘라낸다. (32비트 연산에서는 안전하다)
음수에서는 Math.floor()는 값이 달라진다.
Math.floor( -49.6 ); // -50
~~-49.6; // -49
연산자 우선순위가 ~~이 우선이기에 x | 0 대신 ~~x를 사용해야한다
- 명시적 강제 변환 : 숫자 형태의 문자열 파싱
parseInt()는 문자열을 인자에 넣으면 숫자형 문자까지 변환하고 비숫자형을 만나면 멈춘다.
(왼쪽에서 오른쪽으로 진행하며 비문자열을 만나기 전까지 진행한다)
Number()는 비숫자형 문자가 있다면 NaN을 반환한다.
parseInt()는 문자열에 사용하는 함수이다. 두번째 인자가 없다면 10진수로 처리 (진수 설정이 가능함)
비문자열 파싱
먼저, 비문자열은 parseInt()로 가져가는 것이 잘못됬다.
사용하려면 문자열로 바꾼다음 parseInt()로 시작한다.
const a = {
num: 21,
toString: function(){
return String( this.num * 2 )
},
}
parseInt(a); // 42
무한대 값은 인자로 넘기면 "Infinity"로 변환후 처리해야 한다.
- 명시적 강제 변환 : * → 불리언
! 부정 단항 연산자는 값을 불리언으로 명시적으로 강제 변환한다.
이때, truthy와 falsy 까지 바뀐다.
그래서 !! 이중 부정 연산자로 불리언 값으로 강제변환한다. ( 두번째 ! 이 패리티를 원복한다 )
ToBoolean 강제 변환 모두 Boolean()이나 !!을 사용하지 않고 if()문 등
불리언 콘텍스트에서 암시적 강제변환이 일어난다.
🔰 자료구조의 JSON직렬화시 true/false 값 강제변환도 명시적 ToBoolean 강제변환이다.
삼항 연산자는 표현식의 평가 결과에 따라 true 또는 false를 반환한다.
삼항연산자는 명시적으로 암시적인 강제 변환이 있다.
명시적으로 암시적인 강제 변환은 왠만해서는 쓰지말고 Boolean이나 !!같은 명시적 강제변환을 사용하자.
4. 암시적 변환 : 부수효과가 명확하지 않게 숨겨진 형태로 일어나는 타입변환
- "암시적" 이란?
타입변환시 숨겨진 중간 단계가 있는 상태
- 암시적 강제변환 : 문자열 ⇆ 숫자
1) 숫자 → 문자열 ( +연산자 이용, 숫자의 덧셈◽문자열 접합 )
숫자는 공백 문자열 ""과 더하면 문자열로 강제 변환된다.
const a = 42;
const b = 42 + "";
b; // "42"
2) 문자열 → 숫자 ( -연산자 이용, -0을 빼면 강제변환 )
-연산자는 숫자 뺄셈 기능이 전부이므로 a-0은 a값을 숫자로 강제변환 시킨다.
( a*1, a/1의 연산 역시 마찬가지로 숫자로 강제변환시킨다. )
const a = "3.14";
const b = a - 0;
b; // 3.14
3) 객체에서 사용
valueOf()는 반환이 안되기에 toString()으로 넘어가서 처리한다.
const a = [ 1, 2 ];
const b = [ 3, 4 ];
a + b; // "1, 23, 4"
문자열 변환 후 ( toString()으로 직렬화 ) 숫자로 강제변환된다. 마지막에는 - 연산
const a = [3];
const b = [1];
a - b; // 2
🔰b = a + "" (암시적)을 자바스크립트 프로그램에서 많이 사용한다. ( b = String(a) 보다는)🔰
String()는 toString()를 직접 호출 한다.ToPrimitive 연산 과정에서 a + ""는 a 값을 valueOf() 메서드에 전달하여 호출하고,그 결과값은 ToString() 추상 연산을 하여 최종적인 문자열로 변환된다.두 방법 모두 궁극적으로 변환된 문자열을 반환하지만 원시가 숫자 값이 아닌 객체라면 결과값이 달라질 수 있다.
const a = {
valueOf: function() { return 42; },
toString: function() { return 4; }
}
a + ""; // "42"
String( a ); // "4"
- 암시적 강제변환 : 불리언 → 숫자
복잡한 불리언 로직을 단순한 숫자 덧셈 형태로 단순화 할 때 암시적 강제변환이 빛난다.
불리언 값은 숫자(명시적으로 0 또는 1)로 변환하면 문제가 쉽게 풀린다.
아래는 명시적 강제 변환의 예시이다.
function onlyOne() {
const sum = 0;
for(let i = 0; i < arguments.length; i++){
sum += Number(!!arguments[i]);
// +=에서 암시적 변환이 일어난다
// Number에서 0 또는 1로 강제 변환
// !!arguments[i]에서 인자값을 true/false로 강제변환(비불리언값도 처리가능)
}
return sum === 1;
}
const a = true; // a와 b에 비불리언값을 전달해도 위에서 강제변환이 되므로 상관없다.
const b = false;
onlyOne(b, a); // true
onlyOne(b, a, b, b, b); //true
onlyOne(b, b); // false
onlyOne(b, a, b, b, b, a); // false
- 암시적 강제변환 : * → 불리언
불리언으로의 암시적 강제변환이 일어나는 표현식
- if() 문의 조건 표현식
- for( ; ; ) 문의 두번째 조건 표현식
- while() 및 do ... while() 루프의 조건 표현식
- ? : 삼항 연산자의 첫번째 조건 표현식
- || 및 &&의 좌측 피연산자
위의 5개의 경우에는 ToBoolean 추상연산 규칙에 따라 불리언 값으로 암시적 강제변환된다.
- && 와 || 연산자
이 두 연산자의 결과값은 불리언 값이 아니다.
두 피연산자 중 한쪽의 값이 결과값이 된다.
동작 : &&, || 연산자는 첫번째 피연산자의 불리언 값을 평가한다. ( 비불리언이면 ToBoolean으로 강제변환 후 평가 )
|| 연산자 : 결과가 true면 첫번째 피연산자 값, false면 두번째 피연산자 값을 반환한다.
&& 연산자 : true면 두번째, false면 첫번째 피연산자 값을 반환한다. ( 이러한 특성을 가드연산자라고 한다 )
( 첫번째 피연산자가 false라면 단락평가에 의거하여 두번째 피연산자는 호출되지 않는다 )
a = b || "~~~" 또는 a && b() 같은 관용 코드는 단락평가에 근거한다.
a && ( b || c ) 같은 복합 논리 표현식이 포함된 if문이나 for 루프는 복합 표현식이 평가한다.
→ 불리언으로 암시적 강제변환 순서로 동작한다.
- 심벌의 강제변환
심벌 → 문자열 명시적 강제변환은 허용되나 암시적 강제변환은 금지되며 에러가 난다.
const s1 = Symbol("좋아");
String(s1); // "Symebol(좋아)";
const s2 = Symbol("구려");
s2 + ""; // TypeError
심벌값은 숫자로 절대로 변환되지 않지만,
불리언 값으로는 명시적/암시적 강제변환이 가능하다. ( 항상 true )
5. 느슨한/엄격한 동등비교
느슨한 동등비교 ( Loose Equals ) : == 연산자, 동등함 비교시 강제변환 허용
엄격한 동등비교 ( Strict Equals ) : === 연산자, 동등함 비교시 강제변환 불허용
- 비교 성능
두 동등 비교의 알고리즘은 같다.
- 강제변환이 필요하다면 == 연산자
- 강제변환이 필요없다면 ===연산자
- 추상 동등 비교
비교할 두 값이 같은 타입이면 값을 식별하여 간단히, 자연스럽게 견주어 본다.
예외의 경우
- NaN은 자신과도 동등하지 않다.
- +0 과 -0 은 동등하지 않다.
객체에서 느슨한 동등비교는 두 객체가 같은 레퍼런스일 경우만 동등하다 한다.( 강제변환 X )
타입이 다른 두 값을 느슨한 동등 비교시 한쪽 또는 양쪽 피연산자에서 암시적 강제변환의 방법이 있다.
1) 비교하기 : 문자열 → 숫자
- Type(x)가 Number고 Type(y)가 String이면 x == ToNumber(y) 비교 결과를 반환한다.
- Type(x)가 String고 Type(y)가 Number이면 ToNumber(x) == y 비교 결과를 반환한다.
const a = 42;
const b = "42";
a === b; // false
a == b; // true
느슨한 동등 비교 a == b 에서는 피연산자의 타입이 다르면 비교 알고리즘에 의해 한쪽 또는
양쪽 피연산자 값이 알아서 암시적으로 강제변환된다.
2) 비교하기 : * → 불리언
- Type(x)이 불리언이면 ToNumber(x) == y 의 비교 결과를 반환한다.
- Type(y)이 불리언이면 x == ToNumber(y) 의 비교 결과를 반환한다.
const x = "42";
const y = true;
x == y; // false
Type(y)는 Boolean이며 ToNumber(y)은 1로 강제변환된다. 1 == "42"가 되며, 둘의 타입이 다르므로
재귀적으로 알고리즘을 수행하여 "42"을 42로 바뀌어 1 == 42 → false가 된다.
const x = "42";
const y = false;
x == y; // false
이 코드도 false는 ToNumber(y)로 0으로 강제변환되고, "42" 또한 42로 강제변환 된다.
결국 0 == 42 → false가 된다.
==의 피연산자 중 한쪽이 불리언값이면 그 값을 숫자로 강제변환된다.
if( a == true ) 혹은 if( a === true ) 보다는 if( !!a ) 혹은 if( Boolean(a) )같은 형식으로 사용하는 것이 좋다.
3) 비교하기 : null → undefined
- x가 null이고 y가 undefined면 true를 반환한다.
- x가 undefined이고 y가 null이면 true를 반환한다.
const a = null;
const b;
a == b; // true
a == null; // true
b == null; // true
a == false; // false
b == false; // false
a == ""; // false
b == ""; // false
a == 0; // false
b == 0; // false
null과 undefined를 느슨한 동등비교(==) 하면 서로에게 타입을 마춘다(강제변환).
null과 undefined 자신끼리 비교결과가 true이므로, 이외의 값들과 비교했을 때 결과값이 true일 가능성은 없다.
3) 비교하기 : 객체 → 비객체
객체/함수/배열과 단순 스칼라 원시값의 비교
- Type(x)가 String 또는 Number고 Type(y)가 Object라면, x == ToPrimitive(y)의 비교 결과를 반환한다.
- Type(x)가 Object고 Type(y)가 String 또는 Number라면, ToPrimitive(x) == y의 비교 결과를 반환한다.
const a = "42";
const b = [ 42 ];
a === b; // false
a == b; // true
const c = "abc";
const d = Object(c); // new String(c)와 같다
c === d; // false
c == d; // true
느슨한 동등 비교에서 원시값을 감싼 객체 래퍼를 원시값을 반환하는 과정이다.
d는 ToPrimitive 연산으로 단순 스칼라 원시 값으로 강제변환되었다.
하지만 항상 == 알고리즘에서 위와 같이 동작하는 것은 아니다
const a = null;
const b = Object(a); // Object()와 같다
a == b; // false
const c = undefined;
const d = Object(c); // Object()와 같다
c == d; // false
const e = NaN;
const f = Object(e); // new Number(e)와 같다
e == f; // false
null과 undefined는 객체 래퍼가 따로 없으므로 박싱할 수 없다.
→ Object(null)는 Object()로 해석되어 그냥 일반 객체가 만들어지며 위와 같은 결과가 나온다.
- 희귀 사례
1) 알 박힌 숫자 값
Number.prototype.valueOf = function() {
return 3;
};
new Number(2) == 3; // true
valueOf()를 이용해 부수효과를 주어 값을 지정한다.
2) Falsy 비교
아래의 예시들은 모두 결과가 true가 나오는 것들이다. 이들을 제외한 모든 것 들은 모두 false이다.
// [] == false로 변환
[] == ![]; // true
// ToPrimitive로 강제변환하여 좌변과 우변을 비교가능한 원시값으로 변환
2 == [2]; // true
"" == [null]; // true
// 공백 문자 "", "\n"이 ToNumber를 경유하여 0으로 강제변환 된다.
0 == "\n"; // true
"a" == ["a"]; // true
"0" == 0; // true
긍정 오류로 인한 결과
"" == 0; //true
"" == []; //true
0 == []; //true
// 의미 없는 비교
"0" == false; //true
false == 0; //true
false == ""; //true
false == []; //true
false와 비교하는 것은 의미가 없는거 같으므로 주의해서 코드를 작성하자.....
3) 암시적 강제변환의 안전한 사용법
- 피연산자 중 하나가 true, false일 가능성이 있다면 절대로 ==연산자를 사용하지 말자
- 피연산자 중 하나가 [], "", 0 이 될 수 있다면 가급적 ==연산자는 사용하지 말자
결국은 ==냐 ===냐 문제는 "동등비교시 강제변환의 허용 여부이다".
6. 추상 관계 비교
a < b 와 같은 비교 과정에서 어떤 일들이 벌어지는지 알아보자
추상 관계 비교 알고리즘은 비교시 피연산자 모두 문자열일 때 그 외의 경우 두가지로 나뉜다.
a > b 는 b < a 로 처리된다.
먼저 두 피연산자에 대해 ToPrimitive 강제변환을 실시하는 것으로 시작한다.
어느 한쪽이라도 문자열이 아닐 경우 양쪽모두 ToNumber로 강제변환 하여 숫자값으로 만들어 비교한다.
const a = [42];
const b = ["43"];
a < b; // true
b < a; // false
허나 -0과 +0이 같지 않고, NaN은 무엇과도 같지 않은 유일 값이므로 사용할 때 주의하자
< 비교대상이 모두 문자열 값이면, 각 문자를 단순 어휘(알파벳 순서에 의거) 비교한다
const a = ["42"];
const b = ["043"];
a < b; // false
위의 코드에서 a는 "42", b는 "043"으로 문자 단위로 비교한다.
"0"은 "4" 보다 작은 값이므로 처음부터 실패다.
또한 객체 비교는 불가능하다.
const a = { b: 42 };
const b = { b: 43 };
// a와 b 모두 [object Object]로 변환되어 어휘적으로 비교가 불가능하다.
a < b;
a == b;
a > b;
// 두 객체가 정확히 같은 값에 대한 레퍼런스일 경우만 동등하다.
// 아래의 두 연산은 모두 true이다.
a <= b; // true
a >= b; // true
위의 예시에서 마지막 두 코드를 보도록 하자.
왜 <=와 >=의 연산 결과가 true인가?
그 이유는 <=, >= 두 연산의 결과는 각각 <와 >의 부정을 결과로 전달하기 때문이다.
위의 코드에서는 각각 a<b, a>b의 결과의 부정을 결과로 전달하기에 true가 나온것이다.
7. 정리하기
- 명식적 강제변환은 다른 타입의 값으로 변환하는 의도가 확실한 코드를 말하며 혼동의 여지를 줄이고 코드 가독성 및 유지 보수성을 높일 수 있는 장점이 있다.
- 암시적인 강제변환은 '숨겨진' 로직에 의한 부수 효과가 있으면 타입변환이 처리되는 과정이 명확하지 않다. 그래서 암시적 강제변환이 명시적 강제변환의 정반대고 나쁜것이라 하지만 오히려 코드의 가독성을 높이는 장점도 있다.
'JavaScript > You Don't know JS' 카테고리의 다른 글
I don't know JS YET) 문법 - 연산자 우선순위 (0) | 2022.07.06 |
---|---|
I don't know JS YET) 문법 - 문과 표현식 (0) | 2022.07.05 |
I don't know JS YET 네이티브 (0) | 2022.04.08 |
I don't know JS YET 특수값(값이 아닌 값, undefined, 특수 숫자, 특이한 동등비교, 값과 레퍼런스) (0) | 2022.03.29 |
I don't know JS YET 값( 배열, 문자열, 숫자 ) (0) | 2022.03.25 |