[자바스크립트/Javascript] 강제변환(1)

cool_kim·2021년 7월 11일
0

Javascript

목록 보기
3/7
post-thumbnail

강제변환은 마법? 아니면 사악??

4.1 값변환

강제 변환 : 어떤 값을 다른 타입의 값으로 암시적으로 바꿈
→ 강제 변환 시 객체, 함수 같은 합성 값 타입으로 변환될 수 없음

  • 암시적 강제변환 : 다른 작업 도중 불분명한 부수 효과로부터 발생하는 타입 변환
  • 명시적 강제변환 : 의도적인 타입변환
var a = 42;
var b = a + ""; //암시적 강제변환
var c = String( a ); //명시적 강제변환



4.2 추상 연산

ToString

: 문자열이 아닌 값 → 문자열 변환 작업

  • 숫자
    숫자 : 문자열 반환
    너무 작거나 큰 값 : 지수 형태 문자열로 반환

  • 일반 객체
    특별히 지정하지 않으면 기본적으로 내부 [[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}"
    ```
  1. JSON.stringfy()에 환형 참조 객체(프로퍼티 참조가 무한 순환되는 구조의 객체)를 넘기면 에러 발생

  2. 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]""
  • b는 배열 자체가 아니라 반환된 문자열을 다시 문자열화 함
  1. 대체자가 배열

    • 전체 원소는 문자열이어야함
    • 각 원소는 객체 직렬화의 대상 프로퍼티명
    var a = {
    	b: 42,
    	c: "42",
    	d: [1,2,3]
    };
    
    JSON.stringfy(a, ["b","c"] ); // "b{"b":42,"c":"42"}"
  2. 대체자가 함수

    • 키와 값 두 인자를 전달
    • 처음 한 번은 객체 자신, 다음은 각 개체 프로퍼티별로 한번씩 실행
    • 직렬화 과정에서 해당 키를 건너뛰려면 undefined, 그외엔 해당 값 반환
    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 강제 변환과 연관 됨

  1. 문자열, 숫자, 불리언, null 값이 JSON으로 문자열화하는 방식은 ToStirng 추상 연산의 규칙에 따라 문자열 값으로 강제변환되는 방식과 동일
  2. JSON.stirngfy()에 전달한 객체가 자체 toJSON()메서드를 갖고 있다면 문자열화 전 toJSON()가 자동 호출되어 JSON 안전 값으로 강제변환 됨

ToNumber

: 숫자 아닌 값 → 수식 연산이 가능한 숫자 변환

  • true → 1

  • false → 0

  • undefined → NaN

  • null → 0

  • 문자열 → 숫자 리터럴 규칙/구문 or NaN

  • 0이 앞에 붙은 8진수 → 8진수로 처리하지 않음(일반 10진수로 처리

  • 객체(배열) → 동등한 원시 값으로 변환 후 그 결곽값을 ToNumber 규칙에 의해 강제변환

    • 추상 연산 과정에서 동등한 원시값으로 바꾸기 위해 valueOf() 메서드를 구현했는지 확인
    • 어떻게 해도 원시 값으로 바꿀 수 없을 떄는 TyprError 오류 반환
  • Object.create(null) : 강제변환이 불가능한 객체 생성

ToBoolean

  1. falsy 값

    • undefined
    • null
    • false
    • +0, -0, NaN
    • ""

    📍 falsy 객체
    : 겉보기에는 평범한 객체처럼 작동할 것 같지만 불리언으로 강제변환하면 false

    var a = new Boolean( false );
    var b = new Number( 0 );
    var c = new String( "" );
    
    var d = Boolean( a&& b && c );
    d; // true
  2. truthy 값

    • falsy 값 목록에 없는 값

📌 헷갈리지 않으려면 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();

틸드(~)

: 보수로 변환

  1. 32비트 숫자로 강제 변환
  2. NOT연산

~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
	//못찾음
}

더블 틸드(~~)

: 숫자의 소수점 이상 부분 잘라내기

  1. 맨 앞의 ~는 ToInt32 강제변환을 적용
  2. 각 비트를 거꾸로 함
  3. 두번째 ~는 비트를 또 한 번 뒤집음
  4. 원상태로 되돌림
    ⇒ ToInt32 강제변환만 하는 셈

⚠️ 음수에서는 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같은 명시적 강제변환이 더 좋음

profile
FE developer

0개의 댓글