YOU DON'T KNOW JS 4장

박정훈·2022년 10월 4일
1

YOU DON'T KNOW JS

목록 보기
4/6

말도 많고 탈도 많은 강제 변환... 강제변환의 좋고 나쁨을 충분히 이해하자!

👉값 변환

어떤 값을 다른 타입의 값으로 바꾸는 과정이 명시적이면 타입 캐스팅, 암시적이면 강제변환이라고 한다.

항상 그렇지 않을 수도 있는데 강제변환을 하면 문자열, 숫자, 불리언 같은 스칼라 원시 값 중 하나가 된다. 객체, 함수 같은 합성 값 타입으로 변환되지 않는다. 박싱도 강제변환이 아니다.

const a = 100
const b = a + ""
console.log(typeof b) // string 🤸‍♂️ 암시
console.log(typeof String(a)) // string 🤸‍♂️ 명시

🧐ToString

일반 객체는 특별히 지정하지 않으면 기본적으로 Object.prototype.toString() 메서드가 내부 [[Class]]를 반환한다. 자신의 toString() 메서드를 가진 객체는 문자열처럼 사용하면 자동으로 이 메서드가 호출되어 toString()을 대체한다!

const a = {
    toString: () => {
        return console.log("대체 된 함수입니당!!")
    }
}
const b= {}
a + "" // 대체 된 함수입니당!!
b + "" // '[object Object]'

JSON.stringify()는 인자가 undefined, 함수, 심벌값이면 자동으로 누락시키며 이를 null로 바꾼다. 객체 프로퍼티에 있으면 간단히 지워버린다.

// 부적절한 JSON 값이나 직렬화 하기 곤란한 객체 값을 문자열화하려면 toJSON() 메서드를 따로 정의해야 한다.
// toJSON()의 역할은 '문자열화하기 적당한 JSON 안전 값으로 바꾸는 것'이다.
const a = {
    toJSON: () => {
        console.log("이것이 불리는군요")
    }
}

const b = {
    c: 42,
    d: function() {},
    toJSON: function() {
        return { c: this.c}
    }
}
JSON.stringify(a) // 이것이 불리는군요
JSON.stringify(b) // '{"c":42}'

JSON 인자

JSON.stringify()의 두 번째 선택 인자로 지정하여 객체를 재귀적으로 직렬화하면서 필터링 하는 방법이 있다.

  • 대체자가 배열일 때
    원소는 문자열이어야 하고 각 원소는 객체 직렬화의 대상 프로퍼티명이다. 여기에 포함되지 않은 프로퍼티는 직렬화 과정에서 빠진다.

  • 대체제가 함수일 때
    처음 한 번은 객체 자신에 대해, 그다음엔 각 객체 프로퍼티별로 한 번씩 실행하면서 매번 키와 값 두 인자를 전달한다.

말로 보면 어렵다...

const func = {
    b: 20,
    c: "malza",
    d: [1, 2, 3]
};
JSON.stringify(func, function(k, v){
    if(k !== "b") return v;
}) // '{"c":"malza","d":[1,2,3]}'
JSON.stringify(func, ["d", "c"]); // '{"d":[1,2,3],"c":"malza"}'

세 번째 인자는 스페이스! 사람이 읽기 쉽도록 들여쓰기가 가능하다.

JSON.stringify()은 직접적인 강제변환의 형식은 아니지만 ToString 강제 변환과 연관된다.
1. 문자열, 숫자, 불리어, null 값이 JSON으로 문자열화하는 방식은 ToString 추상 연산의 규칙에 따라 문자열 값으로 강제변환되는 방식과 동일하다.
2. JSON.stringify()에 전달한 객체가 지체 toJSON() 메서드를 갖고 있다면, 문자열화 전 toJSON()가 자동 호출되어 JSON 안전 값으로 강제변환 된다.
...
말이 긴데 그냥 .. JSON.stringify()는 toString 규칙을 따르고, toJSON 메서드를 자체적으로 가지고 있으면 호출된다는 의미겠지.

🧐ToNumber

true는 1, false는 0, undefined는 NaN, null은 0.
valueOf()메서드를 구현했는지 확인, 원시 값이면 강제변환, 그렇지 않으면 toString을 이용해 강제변환

const a = {
    valueOf: () => {
        return "42"
    }
}
const b = {
    toString: () => {
        return "50"
    }
}

const c = [1, 2]
c.toString = function() {
    return this.join("");
}

console.log(Number(a)) // 42
console.log(Number(b)) // 50
console.log(Number(c)) // 12
console.log(Number("")) // 0
console.log(Number([])) // 0 
console.log(Number(["abc"])) // NaN

🧐ToBoolean

자바스크립트에서 숫자는 숫자고, 불리언은 불리언으로 서로 별개다.

Falsy 값

자바스크립트의 모든 값들은

  • boolean으로 강제변환하면 false가 되는 값
  • 위의 값을 제외한 나머지인 true값

그럼 falsy한 값이 뭔데?

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

❗명시적 강제변환

문자열 <-> 숫자

const a = 100
const b = String(a)

const c = "3.14"
const d = Number(c)

날짜 -> 숫자

  • 단항 연산자는 Date 객체를 숫자로 강제변환하는 용도로도 쓰인다.
const timeStamp = +new Date()

but! 이제는 이렇게 쓰지 않아!

// 현재
const timeStamp = Date.now();
// 특정 날씨/시간
const timeStamp = new Date().getTime();

parseInt

parseInt() 는 문자열에 쓰는 함수이다. 문.자.열!

비불리언 -> 불리언

+단항 연산자가 값을 숫자로 경제변환하는 것처럼 ! 부정 단항 연산자도 값을 불리언으로 명시적으로 강제변환한다. 뭐 좋은데, 한 번 더 부정하는 이중부정 연산자 !!를 해야 원래 표현식의 true/false 값을 얻게 된다.

🤔삼항연산자 쓰지말라네 (흠...)

const a = 42;
const b = a ? true: false

삼항 연산자 ? : 는 표현식의 평가 결과에 따라 true 또는 false를 반환한다. 여기에는 암시적 강제변환이 매복하고 있다. a를 일단 불리언으로 강제변환해야 표현식 전체의 true/false여부를 판단할 수 있기 때문이다.

어쨌든 이런 코드는 무조건 쓰지 말자. Boolean(a)이나 !!a 같은 명시적 강제변환이 훨씬 좋다!

아니...! 4장에서 하고 싶은 말이 많은가 보다! 양이 엄청나다..!

👻암시적 변환

여러분들이 보기에 분명하지 않은 타입변환은 모두 이 범주에 속한다! 자바스크립트 강제변환으르 향한 대부분의 불평불만이 바로 암시적 강제변환을 겨냥하고 있는 건 사실이다. 그렇다면 임시적 강제변환은 정말 유해하고 위험한가?!

문자열 <-> 숫자

+연산자는 숫자의 덧셈, 문자열 접합 두가지 목적으로 오버로드 된다.

const a ="42"
const b = "0"

const c = 42
const d = 0

a + b = "420"
c + d = 42

+연산의 한쪽 피연산자가 문자열이면 +는 문자열 붙이기 연산을 한다. 그 밖에는 언제나 숫자 덧셈을 한다! 다만 주의해야 할 점은 암시적 강제변환은 valueOf() 메서드에 전달하여 호출하고, 그 결과값을 ToString 추상 연산을 하여 최종적인 문자열로 변환하고, String()은 toString()를 직접 호출할 뿐이다.

const a = {
  valueOf: () => 42,
  toString: () => 4
}

a + "" // "42"
String(a) // "4"

직접 valueOf(), toString() 메서드를 구현한 객체가 있다면 결과값이 달라질 수 있다!

-연산자는 숫자 뺄셈 기능이 전부이다.

let a = "3.14"
const b = a - 0

b // 3.14 -> a를 숫자로 강제변환한다.

느슨한/엄격한 동등 비교

동등함의 비교 시 ==는 강제변환을 허용하지만, ===는 강제변환을 허용하지 않는다.

profile
그냥 개인적으로 공부한 글들에 불과

0개의 댓글