객체를 원시형으로

김하은·2023년 5월 10일
0

객체끼리 더하거나, 객체끼리 빼는 연산, 객체를 출력하는 등의 경우에는 자동 형변환이 일어나게 된다.
객체는 원시값으로 변환되고, 그 후 의도한 연산이 일어난다.

  1. 객체는 논리 평가시 true를 반환한다. 예외는 없다.
    객체는 숫자형이나 문자로만 형변환된다.
  2. 숫자형으로의 형변환은 객체끼리 빼는 연산을 하거나 수학 관련 함수를 적용할 때 일어난다. 객체 Date끼리 빼는 연산을 진행하면 두 날짜간의 차이를 볼 수 있다.
  3. 문자형으로의 형변환은 보통 alert(obj)같이 객체를 출력하려고 할 때 일어나게된다.

ToPrimitive

특수 객체 메서드를 사용하면 숫자형이나 문자형으로의 형변환을 원하는대로 조절할 수 잇따.
객체의 형변환은 세가지로 구분된다.
'hint'라고 불리는 값이 구분기준.이것은 목표로 하는 자료형 정도로 이해할 수 있다.

  • alert함수같이 문자열을 기대하는 연산을 수행하고자할때에는 hint가 문자열 (string)이 된다.

  • 수학연산을 적용하려고 할때 (객체-숫자형변환) hint가 number이된다.

// 명시적 형 변환
let num = Number(obj);
>
// (이항 덧셈 연산을 제외한) 수학 연산
let n = +obj; // 단항 덧셈 연산
let delta = date1 - date2;
>
// 크고 작음 비교하기
let greater = user1 > user2;
  • 연산자가 기대하는 자료형이 확실치 않을 시 hint는 default가 된다.(드물게 발생)

이항덧셈연산자는 피연산자의 자료형에 따라 문자열을 합치는 연산을 할 수도 있고, 숫자를 더해주는 연산을 할 수도 있다. 따라서 +의 인수가 객체일때는 hint가 default가 된다.

동등연산자 ==를 사용해 객체-문자형, 객체-숫자형, 객체-심볼형끼리 비교시에도 객체를 어떤 자료형으로 바꿔야될지 확신이 서지 않으므로 hint는 default가 된다.

boolean hint는 없다.
hint는 총 세가지뿐이다. 모든 객체는 true이기때문이다.

자바스크립트는 형변환이 필효할 때 아래와 같은 알고리즘에 따라 원하는 메서드를 찾고 호출한다.

  1. 객체에 objSymbol.toPrimitive메서드가 있는지 찾고, 있다면 메서드를 호출합니다.
    • Symbol.toPrimitive는 시스템 심볼로, 심볼형 키로 사용됩니다.
  2. 1에 해당하지 않고 hint가 "string"이라면,
    • obj.toString()이나 obj.valueOf()를 호출합니다(존재하는 메서드만 실행됨).
  3. 1과 2에 해당하지 않고, hint가 "number"나 "default"라면
    • obj.valueOf()나 obj.toString()을 호출합니다(존재하는 메서드만 실행됨).

Symbol.toPrimitive

자바스크립트에는 Symbol.toPrimitive 라는 내장심볼이 존재한다. 이 심볼은 아래와 같이 목표로 하는 자료형(hint)를 명명하는데 사용된다.

obj[Symbol.toPrimitive] = function(hint) {
  // 반드시 원시값을 반환해야 합니다.
  // hint는 "string", "number", "default" 중 하나가 될 수 있습니다.
};

toString과 valueOf

toString과 valueOf 는 심볼이 생기기 이전부터 존재해왔던 평범한 메서드이다.
이것을 이용하면 구식이지만 형변환을 직접 구현할 수 있다.
객체에 Symbol.toPromitive가 없다면 자바스크립트는 toString이나 valueOf 를 호출한다.

  • hint가 string인 경우: toString => valueOf순으로 호출(toString이 있다면 toString을 호출, toString이 없다면 valueOf를 호출함)
  • 그 외 : valueOf => toString 순

이 메서드들은 반드시 원시값을 반환해야한다. 객체를 반환하면 그 결과는 무시된다.(마치 메서드가 처음부터 없었던것처럼)

일반 객체는 기본적으로 toString과 valueOf에 적용되는 다음 규칙을 따른다.

toString은 문자열 "[object Object]"을 반환한다.
valueOf는 객체 자신을 반환한다.

let user = {name: "John"};

alert(user); // [object Object]
alert(user.valueOf() === user); // true

이러한 이유로 alert에 객체를 넘기면[object Object] 가 출력되는것.

반환타입

위의 세개의 메서드는 hint에 명시된 자료형으로의 형변환을 보장해주지 않는다.
toString()이 항상 문자열을 반환하리라는 보장이 없고 Symbol.toPrimitive 의 hint가 number일때 항상 숫자형이 반환되리라는 보장도 없다.

한가지 확실한것은 원시값을 반환한다는 것이다.

과거의 잔재
toString이나 valueOf가 객체를 반환해도 에러는 없다. 다만 이때는 반환값이 무시되고 메서드가 원래 없었던것처럼 동작한다.
이것은 과거 자바스크립트에는 '에러' 라는 개념이 잘 정립되어있지 않았기 때문이다.

반면, Symbol.toPrimitive 는 무조건 원시형 자료를 반환해야 에러가 없다.

추가 형변환

상당수의 연산자와 함수가 피연산자의 형을 변환시킨다. 곱셈을 해주는 연산자는 피연산자를 숫자형으로 변환시킨다.

객체가 피연산자일때는 아래와 같은 단계를 거쳐 형변환이 일어난다.

  1. 객체는 원시형으롭 변환된다.
  2. 변환 후 원시값이 원하는 형이 아닌경우 또다시 형변환이 일어난다.
let obj = {
  toString() {
    return "2";
  }
};

alert(obj + 2); // 22("2" + 2), 문자열이 반환되기 때문에 문자열끼리의 병합이 일어났습니다.

이번정리는 정리하면서도 무슨말인지 모르겠다. 일단 다 정독해본뒤 후에 다시 정리를 해봐야겠다.

0개의 댓글