강제변환은 마법? 아니면 사악??
강제 변환 : 어떤 값을 다른 타입의 값으로 암시적으로 바꿈
→ 강제 변환 시 객체, 함수 같은 합성 값 타입으로 변환될 수 없음
var a = 42;
var b = a + ""; //암시적 강제변환
var c = String( a ); //명시적 강제변환
: 문자열이 아닌 값 → 문자열 변환 작업
숫자
숫자 : 문자열 반환
너무 작거나 큰 값 : 지수 형태 문자열로 반환
일반 객체
특별히 지정하지 않으면 기본적으로 내부 [[Class]] 반환 ex) [object Object]
배열
모든 원소 값이 콤마(,)로 분리된 형태로 반롼 ex) "1,2,3"
JSON
✔️ JSON.stringfy()
: 어떤 값을 JSON 문자열로 직렬화
→ 강제변환과 똑같지 않지만 ToString 규칙과 관련됨
1. JSON 안전 값(JSON으로 확실히 나타낼 수 있는 값)은 모두 JSON.stringfy()로 문자열화 가능
2. JSON 안전 값이 아닌 것들은 자동으로 누락시키며 이런 값이 배열에 들어있으면 null로 바꿈
```javascript
JSON.stringfy( undefined ); //undefined
JSON.stringfy( function(){} ); //undefined
JSON.stringfy(
[1,undefined,function(){},4]
); // "[1,null,null,4]"
JSON.stringfy(
{ a:2, b:function(){} }
); //"{"a":2}"
```
JSON.stringfy()에 환형 참조 객체(프로퍼티 참조가 무한 순환되는 구조의 객체)를 넘기면 에러 발생
JSON.stringfy()의 세번째 인자는 '스페이스' : 들여 쓰기를 할 빈 공간의 개수를 숫자로 지정하거나 문자열을 지정하여 각 들여쓰기 수준에 사용
var a = {
b: 42,
c: "42",
d: [1,2,3]
};
JSON.stringfy( a, null, 3 );
// "{
// "b": 42,
// "c": "42",
// "d": [
// 1,
// 2,
// 3
// ]
// ]"
JSON.stringfu( a, null, "-----" );
// "{
// -----"b": 42,
// -----"c": "42",
// -----"d": [
// ----------1,
// ----------2,
// ----------3
// -----]
// }"
✔️ toJSON() : 해당 객체의 JSON 안전 버전 반환
→ JSON문자열로 바꾸는 것이 아님
```javascript
var a = {
val: [1,2,3],
toJSON: function() {
return this.val.slice( 1 );
}
};
var b = {
val: [1,2,3],
toJSON: function(){
return "[" +
this.val.slice( 1 ).join() +
"]";
}
};
JSON.stringfy(a); // "[2,3]"
JSON.stringfy(b); // ""[2,3]""
var a = {
val: [1,2,3],
toJSON: function() {
return this.val.slice( 1 );
}
};
var b = {
val: [1,2,3],
toJSON: function(){
return "[" +
this.val.slice( 1 ).join() +
"]";
}
};
JSON.stringfy(a); // "[2,3]"
JSON.stringfy(b); // ""[2,3]""
대체자가 배열
var a = {
b: 42,
c: "42",
d: [1,2,3]
};
JSON.stringfy(a, ["b","c"] ); // "b{"b":42,"c":"42"}"
대체자가 함수
var a = {
b: 42,
c: "42",
d: [1,2,3]
};
JSON.stringfy( a, function(k,v) {
if (k !== "c") return v;
});
// "{"b":42,"d":[1,2,3]}"
JSON.stringfy()은 직접적인 강제 변환의 형식은 아니지만 두 가지 이유로 ToString 강제 변환과 연관 됨
: 숫자 아닌 값 → 수식 연산이 가능한 숫자 변환
true → 1
false → 0
undefined → NaN
null → 0
문자열 → 숫자 리터럴 규칙/구문 or NaN
0이 앞에 붙은 8진수 → 8진수로 처리하지 않음(일반 10진수로 처리
객체(배열) → 동등한 원시 값으로 변환 후 그 결곽값을 ToNumber 규칙에 의해 강제변환
Object.create(null) : 강제변환이 불가능한 객체 생성
falsy 값
📍 falsy 객체
: 겉보기에는 평범한 객체처럼 작동할 것 같지만 불리언으로 강제변환하면 false
var a = new Boolean( false );
var b = new Number( 0 );
var c = new String( "" );
var d = Boolean( a&& b && c );
d; // true
truthy 값
📌 헷갈리지 않으려면 falsy 값을 외워두는 것이 좋음!
: 분명하고 확실한 타입변환
: String(), Number() 사용
⚠️ 앞에 new 키워드가 붙지 않기 때문에 객체 래퍼 생성하는 것이 아님
toString()
: 겉보기에는 명시적이지만 암시적인 요소 감춰져 있음
→ 원시값 42에는 toStirng() 메소드가 없으므로 엔진은 toStirng을 자용 할 수 있게 자동으로 42를 객체 래퍼로 '박싱'함
+c
: 단한 연산자로 덧ㅅ겜을 하는게 아니라 피연산자 c를 숫자로 하는 명시적 강제변환
var c = "3.14";
var d = 5+ +c;
d; // 8.14
⚠️ var d = 5+ +c;
두 부호 사이에 띄어 쓰기를 하지 않으면 증감 연산자가 되어버리니 조심!
: + 단항 연산자 사용
var d = new Date( "Mon, 18 Aug 2014 08:53:06 CDT" );
+d; // 1408369986000 (유닉스 타임스탬프 표현형)
📍 현재 시각을 타임스탬프로 바꿀 때 : var timestamp = +new Date();
📍 강제변환 없이 Date 객체로부터 타임스탬프 얻기
var timestamp = new Date().getTime();
//var timestamp = (new Date()).getTime();
//var timestamp = (new Date).getTime();
var timestamp = Date.now();
: 보수로 변환
~x
는 -(x+1)
과 같음
~42; // -(42+1) ==> -43
✔️ -(x+1)을 0으로 만드는 값은 -1이다.
→ -1이면 falsy한 0, 그 외에는 truthy한 숫자 값이 산출
📍 여기서 -1과 같은 성질의 값은 '경계값'이라고 함
- 경계값 : 동일 타입의 더 확장된 값의 집합 내에서 임의의 어떤 의미를 부여한 값
ex) indexOf() 에서 인덱스를 발견하지 못했을 경우 -1을 반환
var a = "Hello World";
~a.indexOf( "lo" ); // -4 <-- truthy
if(~a.indexOf( "lo" )) { // true
//찾음
}
~a.indexOf( "ol" ); // 0 <-- falsy
!~a.indexOf( "ol" ); // 0 <-- true
if(!~a.indexOf( "ol" )) { // true
//못찾음
}
더블 틸드(~~)
: 숫자의 소수점 이상 부분 잘라내기
⚠️ 음수에서는 Math.floor()과 결과값이 다름
~~1E20 / 10; //166199296
1E20 | 0 /10; //1661992960
(1E20 | 0) / 10; //166199296
: 문자열 → 숫자 강제 변환과 결과가 비슷하지만 비숫자형 문자를 허용함
var a = "42";
var b = "42px";
Number( a ); //42
parseInt( a ); //42
Number( b ); //NaN
parseInt( b ); //42
: 비불리언 → 불리언 강제변환
: Boolean(), !! 로 강제 변환
📍 삼항 연산자
var b = a ? true : false;
✔️삼항 연산자보다 Boolean(a)나 !!a같은 명시적 강제변환이 더 좋음