회고록 블로그

[공부 필기] JavaScript 문법 공부 23일차 (2) 본문

2. 프로그래밍 언어 공부/JavaScript

[공부 필기] JavaScript 문법 공부 23일차 (2)

김간장 2022. 5. 24. 22:27

※ 필자는 초초초보자입니다.

※ 틀린 내용에 대한 피드백은 언제든지 환영합니다.

 

 

공부하고 있는 자료 : modern JavaScript tutorial 

https://ko.javascript.info/object-toprimitive

 

객체를 원시형으로 변환하기

 

ko.javascript.info

 

✅ 객체 -> 원시형 변환하기

- 객체끼리 더하거나 빼면? 자동 형 변환이 일어난다.

   ► 객체는 원시값으로 변환된다.

 

- 변환 규칙

   ► 객체는 논리 평가 시 true를 반환 = 객체는 숫자형이나 문자형으로만 형 변환이 일어난다.

   ► 수학 관련 함수를 적용할 때 숫자형으로 형 변환이 된다.

   ► alert 등으로 객체를 출력할 때 문자형으로 형 변환이 된다.

 

✅ ToPrimitive

- 객체 형 변환은 세 종류로 구분된다.

   ► hint(라고 불리는 값)가 구분 기준이 된다.

   ► hint : 목표로 하는 자료형

 

- 예시

   ► alert 함수는 문자열을 기대하는 연산이므로 hint는 string이 된다.

"use strict";

let user = {};

alert(user);

   ► 수학 연산을 적용할 때 hint는 number가 된다.

"use strict";


let user1 = {}; // object

let user2 = Number(user1); // 명시적 형 변환
let user3 = +user1; // 단항 덧셈 연산

console.log(typeof user2); //number
console.log(typeof user3); //number

let subtract = user1 - 0; //수학 연산

console.log(typeof subtract); //number

   ► 연산자가 기대하는 자료형이 '확실치 않을 때' hint는 default가 된다.

        /* 이항 덧셈 연산자(+)는 피연산자가 문자열이면 문자를 합치게 되고

            피연산자가 숫자이면 값을 더하는 연산이 될 수 있기 때문에

            피연산자가 객체가 되면 hint는 default가 된다. */

   ► 동등 연산자(==)를 사용해서 객체-문자형, 객체-숫자형, 객체-심볼형을 비교할 때도

        객체를 어떤 자료형으로 바꿔야할지 확실치 않으므로 hint는 default가 된다.

 

📌 비교 연산자(<, >)

- 피연산자에 문자형과 숫자형이 모두 올 수 있다.

- 하지만 이 연산자는 hint를 number로 고정한다.

- 이는 하위 호환성 때문에 정해진 규칙이다.

 

📌 boolean은 hint가 될 수 없다.

- hint의 종류는 총 3가지이다. (string, number, default)

- boolean은 존재하지 않는다.

- 다만 boolean은 없지만, 모든 객체는 항상 true로 평가된다.

 

✅ 자바스크립트가 형 변환을 할 때

- 자바스크립트는 형 변환을 해야할 때 아래의 알고리즘에 따라 동작한다.

 

1) 객체에 obj[Symbol.toPrimitive](hint) 메서드가 있는지 찾는다.

2) 해당 메서드가 있으면 메서드를 호출한다.

     ► Symbol.toPrimitive는 시스템 심볼이다. 심볼형 키로 사용된다.

3) 해당 메서드가 없으면 hint가 "string"인지 확인하고

     "string"이면 obj.toString() 또는 obj.valueOf()를 호출한다.

     (존재하는 메서드만 실행된다. toString이 있다면 toString을 호출, toString이 없다면 valueOf를 호출한다.)

4) 1, 2, 3이 모두 아니라면 hint가 "number" 또는 "default"인지 확인하고

     맞다면 obj.valueOf() 또는 obj.toString()을 호출한다.

     (존재하는 메서드만 실행된다. valueOf가 있다면 valueOf를 호출, valueOf가 없다면 toString을 호출한다.)

 

 

※ 용어 정리

- 심볼형 키를 만들 때는 대괄호를 사용한다고 했었다.

- 프로퍼티의 키가 심볼형인 것

"use strict";

let id = Symbol("id");

let user = {
	name: 'soy',
	[id]: 0411, //"id": 0411 을 하면 심볼이 아니라 문자열 id가 된다.
}

 

✅ Symbol.toPrimitive

- 자바스크립트에는 Symbol.toPrimitive라는 내장 심볼이 있다.

- 이 심볼은 목표로 하는 자료형(=hint)을 명명하는 데 사용된다.

 

- 아래의 코드는 user1 객체에 프로퍼티를 추가하는 코드이다.

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

 

무슨 소리인지 이해가 안되어서 예시를 가져왔다.

"use strict";

// object
let user1 = {
	value1: 10,
	value2: 'Money',

	[Symbol.toPrimitive]: function(hint) {
		console.log(`hint: ${hint}`);
		return (hint == "number" || hint == "default") ? this.value1 : `${this.value2}`;
	}
	

};

console.log(user1); // {value1: 10, value2: 'Money', Symbol(Symbol.toPrimitive): ƒ} 출력
console.log(+user1); // hint: number 와 10 출력
console.log(user1 + 20); // hint: default 와 30 출력

- 이렇게 구현해 놓으면 객체 user의 hint에 따라 출력되는 값이 달라진다고 한다. (형 변환이 달라지므로)

   user1[Symbol.toPrimitive]를 사용하면 메서드 하나로 모든 종류의 형 변환을 다를 수 있다.

 

📌 Symbol.toPrimitive

- 앞서 자바스크립트가 형 변환을 필요로 할 때의 알고리즘에 대해 언급하면서

첫번째 순서로 아래의 과정을 수행한다고 했었다.

1) 객체에 obj[Symbol.toPrimitive](hint) 메서드가 있는지 찾는다.

객체 user1에게 형 변환이 필요할 때 obj[Symbol.toPrimitive](hint) 메서드를 찾게 되고

위의 코드는 해당 메서드가 정의되어 있기 때문에 호출해서 그 안의 코드를 실행한 것.

 

 

✅ toString과 valueOf

- 형 변환을 직접 구현할 때 사용할 수 있는 메서드이다. 근데 그렇게 형 변환하는 것은 구식이라고 한다.

 

- 앞서 자바스크립트가 형 변환을 할 때의 알고리즘을 아래와 같이 언급했었다.

3) 해당 메서드가 없으면 hint가 "string"인지 확인하고 "string"이면 obj.toString() 또는 obj.valueOf()를 호출한다.
     (존재하는 메서드만 실행된다. toString이 있다면 toString을 호출, toString이 없다면 valueOf를 호출한다.)
4) 1, 2, 3이 모두 아니라면 hint가 "number" 또는 "default"인지 확인하고 맞다면 obj.valueOf() 또는 obj.toString()을 호출한다.
     (존재하는 메서드만 실행된다. valueOf가 있다면 valueOf를 호출, valueOf가 없다면 toString을 호출한다.

- 정리하자면

hint == "string"이면 → toString 호출 → toString이 없다면 valueOf 호출

hint == "string 외" 이면 → valueOf 호출 → valueOf가 없다면 toString 호출

 

- toString과 valueOf 메서드는 반드시 원시값을 반환해야한다.

   ► 만약 toString과 valueOf의 반환값이 [객체]이면,

       그 결과는 무시되고 마치 이 메서드들이 없었던 것처럼 동작된다.

- 두 메서드는 기본적으로 아래와 같이 반환한다.

   ► toString : 문자열 "[object Object]" 반환

   ► valueOf : 객체 자신을 반환

 

 

📌 사실 valueOf는 객체 자신을 반환(객체를 반환)하기 때문에, 그 결과가 무시되며

    valueOf라는 메서드가 존재하지 않는 것처럼 되어버린다.

- 그래서 그런지 아래와 같은 경우는 수학과 관련된 연산을 해도 결과값이 -10이 되지 않는다.

"use strict";

// object
let user1 = {
	value1: 10,
	value2: 'Money',
};

console.log(user1 - 20); // NaN

- 만약 Symbol.toPrimitive나 toString, valueOf가 객체 안에 정의되어 있다면 다른 결과가 나왔을 것

"use strict";

// object
let user1 = {
	value1: 10,
	value2: 'Money',

	valueOf() {
		return this.value1;
	}
};

console.log(user1 - 20); // -10

- 메서드명과 맞지는 않지만 toString 메서드에서 숫자형(문자형 X)을 반환하도록 할 수도 있다.

   ► toString이 반드시 문자열만을 반환하리라는 보장을 할 수 없다는 의미이다.

"use strict";

// object
let user1 = {
	value1: 10,
	value2: 'Money',

	toString() {
		return this.value1;
	}
};

console.log(user1 - 20); // -10

 

- 만약 hint가 string이거나 number이거나 default이거나 상관없이

   모든 형 변환을 한 곳에서 처리해야 하는 경우라면 toString만 구현해도 된다.

   ► toString만 사용해도 모든 변환을 다 다룰 수 있기 때문에 실무어세는 toString만 구현해도 충분한 경우가 많다고 한다.

   ► 로깅이나 디버깅 목적으로도 사용된다고 한다.

 

✅ 반환 타입

- toString이나 valueOf의 반환값으로 [객체]가 오면

   마치 해당 메서드가 없는 것처럼 동작한다.

- 하지만 Symbol.toPrimitive는 반환값으로 원시형 외의 값이 오면 에러가 발생한다.

 

   

 

 

Comments