코딩일상
[JavaScript 33가지 지식] 명시적변환, 암시적 변환, 명칭적 타이핑, 구조적 타이핑, 덕 타이핑 본문
[JavaScript 33가지 지식] 명시적변환, 암시적 변환, 명칭적 타이핑, 구조적 타이핑, 덕 타이핑
solutionMan 2022. 11. 30. 13:39
들어가기 앞서
형변환에 대해 설명을하고 내용에 들어가겠다.
형변환이란?
프로그램을 작성하면서 문자를 숫자로, 숫자를 문자로 변환해야한는 경우가 생긴다.
이렇게 타입형태를 바꾸는 것을 형변환이라고 하며, 형변환에 방법에는 명시적 변환, 암시적 변환이 존재한다.
명시적 변환이란?
명시적 변화은 개발자가 의도적으로 형변환을 하는것이다.
기본적인 형변환은 Object(),Nubmer(),String(), Boolean()과 같은 함수를 이용한다.
let variable = 100
console.log(variable, typeof variable) // 100 "number"
variable = Object(variable)
console.log(variable, typeof variable) // Number {100} "object"
variable = String(variable)
console.log(variable, typeof variable) // 100 "string"
variable = Boolean(variable)
console.log(variable, typeof variable) // true "boolean"
원래 Object(),Nubmer(),String()과 같은 함수는 생성자 함수이다.
하지만 new 연산자가 없을 경우 형변화에 사용된다.
Number Type으로 변환하기
Number가 아닌 다른 자료형을 Number로 변환하는 방법은 아래와같다.
1)Number()
정수형과 실수형 데이터를 숫자로 변환하고 숫자 데이터가 아닌 것은 NaN을 반환한다.
Boolean 데이터인 true와 false는 각각 1과 0으로 변환된다.
console.log(Number('100000'), typeof Number('100000')) // 100000 "number"
console.log(Number('5' * 5), typeof Number('5' * 5)) // 25 "number"
console.log(Number('3.14'), typeof Number('3.14')) // 3.14 "number"
console.log(Number('a'), typeof Number('a')) // Nan "number"
console.log(Number(true), typeof Number(true)) // 1 "number"
console.log(Number(false), typeof Number(false)) // 0 "number"
2)parseInt()
parseInt()함수는 정수형의 숫자로 변환된다.
문자열이 숫자0으로 시작시 8진수로 인식하고,0x,0X로 시작시 16진수로 인식한다.
또한 숫자가 아닌 데이터가 먼저 포함된 문자열이 들어올 경우NaN을 반환한다.
*Number와 다르게 true,false을 NaN으로 반환한다.
console.log(parseInt('100000'), typeof parseInt('100000')) // 100000 "number"
console.log(parseInt('3.14'), typeof parseInt('3.14')) // 3 "number"
console.log(parseInt('a'), typeof parseInt('a')) // NaN "number"
console.log(parseInt(011), typeof parseInt(011))//8진수 여서 9
console.log(parseInt(0x11), typeof parseInt(0x11))//16진수 여서 17
console.log(parseInt(true), typeof parseInt(true)) // NaN "number"
console.log(parseInt(false), typeof parseInt(false)) // NaN "number"
3)parseFloat()
parseFloat()함수는 실수형의 숫자로 변환
parseInt()와 비슷하지만 16진수 문자열 데이터("0x27")일 경우 0을 반환
console.log(parseFloat('100'), typeof parseFloat('100')) // 100 "number"
console.log(parseFloat('2.14'), typeof parseFloat('2.14')) // 2.14 "number"
console.log(parseFloat('a'), typeof parseFloat('a')) // NaN "number"
console.log(parseFloat('A'), typeof parseFloat('A')) // NaN "number"
console.log(parseFloat(0033), typeof parseFloat(0033)) // 27 "number"
console.log(parseFloat('0033'), typeof parseFloat('0033')) // 33 "number"
console.log(parseFloat(0x1b), typeof parseFloat(0x1b)) // 27 "number"
console.log(parseFloat('0x1b'), typeof parseFloat('0x1b')) // 0 "number"
console.log(parseFloat(true), typeof parseFloat(true)) // NaN "number"
console.log(parseFloat(false), typeof parseFloat(false)) // NaN "number"
console.log(parseFloat(() => {}), typeof parseFloat(() => {})) // NaN "number"
console.log(parseFloat(' 2'), typeof parseFloat(' 2')) // 2 "number"
console.log(parseFloat(' 2 '), typeof parseFloat(' 2 ')) // 2 "number"
console.log(parseFloat(' 2 ㄴ2'), typeof parseFloat(' 2 ㄴ2')) // 2 "number"
console.log(parseFloat(' ㄴ2'), typeof parseInt(' ㄴ2')) // Nan "number"
String Type으로 변환하기
1)String()
console.log(String(10000), typeof String(10000)) // "10000" "string"
console.log(String(3.14), typeof String(3.14)) // "3.14" "string"
console.log(String(true), typeof String(true)) // "true" "string"
console.log(String(false), typeof String(false)) // "false" "string"
console.log(String(() => {}), typeof String(() => {})) // "() => {}" "string"
console.log(String({ foo: 'bar' }), typeof String({ foo: 'bar' })) // "[object Object]" "string"
number나 boolean데이터 그리고 () => {}같은 함수도 문자열로 바뀌는 것을 확인할 수 있다.
{ foo: "bar" }와 같은 객체도 string으로 변환되긴하지만 [object Object]와 같이 표시된다.
2)toString()
console.log((10000).toString(), typeof (10000).toString()) // "10000" "string"
console.log((10000).toString(2), typeof (10000).toString(2)) // "10011100010000" "string"
console.log((10000).toString(8), typeof (10000).toString(8)) // "23420" "string"
console.log((3.14).toString(), typeof (3.14).toString()) // "3.14" "string"
console.log(true.toString(), typeof true.toString()) // "true" "string"
console.log(false.toString(), typeof false.toString()) // "false" "string"
console.log((() => {}).toString(), typeof (() => {}).toString()) // "() => {}" "string"
console.log({ foo: 'bar' }.toString(), typeof { foo: 'bar' }.toString()) // "[object Object]" "string
toString()함수도 String()과 비슷하지만
차이점이 있다면 number데이터를 변환할 때 진수를 지정할 수 있다.
인자를 전달하지않으면 기본적으로 10진수 값으로 number데이터를 string으로 변환한다.
3)toFixed()
toFixed()는 number데이터에만 사용할 수 있다.
인자에 주는 값은 인자의 값만큼 소수점 자리수를 표현한다.
console.log((10000).toFixed(), typeof (10000).toFixed()); // "10000" "string"
console.log((10000).toFixed(2), typeof (10000).toFixed(2)); // "10000.00" "string"
console.log((10000).toFixed(3), typeof (10000).toFixed(8)); // "10000.000" "string"
console.log((3.14).toFixed(), typeof (3.14).toFixed()); // "3" "string"
console.log((3.14).toFixed(1), typeof (3.14).toFixed()); // "3.1" "string"
console.log((3.16).toFixed(1), typeof (3.16).toFixed()); // "3.2" "string"
console.log(("문자").toFixed(1), typeof (3.16).toFixed()); //TypeError
console.log(("abc").toFixed(1), typeof (3.16).toFixed()); // TypeError
Boolean Type으로 변환하기
1)Boolean()
Boolean으로 변환하기 위해서는 Boolean()을 사용한다.
0, Nan, null, undefined가 아닌 값들은 모두 true로 변환된다.
Boolean(100); //true
Boolean(“1”); //true
Boolean(true); //true
Boolean(Object); //true
Boolean([]); //true
Boolean(0); //false
Boolean(NaN); //false
Boolean(null); //false
Boolean(undefined); //false
암시적 변환(Implicit Conversion)
암시적 변환은 자바스크립트 엔진이 자동으로 데이터 타입을 변환시키는 것이다.
아래와 같은 결과가 암시적변환의 예시이다.
number = 10;
string = "10";
console.log(number + string, typeof(number + string));//1010 string
다른 언어일 경우 아래와 같이 에러메세지를 발생시켰을 것이다.
number = 10
string = "10"
print(number + string, type(number + string))
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# TypeError: unsupported operand type(s) for +: 'int' and 'str'
일반적인 언어에서는 타입이 다른 값들의 연산은 지원하지 않지만 자바스크립트는 가능하다.
자바스크립트가 타입에 대하여 상당히 유연한 언어인 이유기이기도 하다.
이뿐만 아니라 암시적 변환은 산술연산자와 동등 연산자를 사용할때도 발생한다.
산술 연산자에서의 암시적 변환
1)더하기 연산자 (+)
더하기 연산자에서는 문자의 우선순위가 숫자보다 높다.
객체와 함수또한 문자보다 우선순위가 낮다.
결론: 더하기 연산자에서는 String의 우선순위가 가장높다.
- Number + String =>String
- String + Boolean =>String
- String + Object =>String
//Number + String
console.log(10 + '10', typeof (10 + '10')) // "1010" "string"
console.log(10 + 'abc', typeof (10 + 'abc')) // "10abc" "string"
//String + Boolean
console.log('abc' + true, typeof ('abc' + true)) // "abctrue" "string"
console.log('abc' + false, typeof ('abc' + true)) // "abcfalse" "string"
//String + Object
console.log('abc' + { foo: 'bar' }, typeof ('abc' + { foo: 'bar' })) // "abc[object Object]" "string"
console.log('abc' + (() => {}), typeof ('abc' + (() => {}))) // "abc() => {}" "string"
2)그 외 연산자 (-, *, /, %)
더하기 연산자를 제외한 연산자에서는 숫자의 우선순위가 문자보다 높다.
숫자가 아닌 "abc"같은 문자열이 들어갈 경우 연산이 불가능해 Nan이 반환된다.
- Number * String=>Number
- Number - String=>Number
- Number / String=>Number
- Number % String=>Number
- Number (*, -, /, %) Boolean=>Number
console.log(10 * '10', typeof (10 * '10')) // 100 "number"
console.log(10 * 'abc', typeof (10 * 'abc')) // Nan "number"
console.log(10 - '10', typeof (10 - '10')) // 0 "number"
console.log(10 - 'abc', typeof (10 - 'abc')) // Nan "number"
console.log(10 / '10', typeof (10 / '10')) // 1 "number"
console.log(10 / 'abc', typeof (10 / 'abc')) // Nan "number"
console.log(10 % '10', typeof (10 % '10')) // 0 "number"
console.log(10 % 'abc', typeof (10 % 'abc')) // Nan "number"
console.log(10 * true, 10 * false) // 10 0
console.log(10 - true, 10 - false) // 9 10
console.log(10 / true, 10 / false) // 10 Infinity
console.log(10 % true, 10 % false) // 0 Nan
3)동등연산자
==연산자를 사용할 경우에도 암시적 변환이 발생한다.
console.log(0 == '0') // true
console.log(0 == false) // true
console.log('0' == false) // true
console.log(undefined == null) // true
console.log('' == false) // true
console.log('' == 0) // true
console.log('' == '0') // false
위와 같이 Number타입인 0과 String타입인 "0"은 ==연산자를 사용할 경우 같다.
또한 0과 "0"은 Boolean타입인 false와 같다는 것을 확인할 수 있다.
비어있는 문자열인 ""은 false와 0과는 같지만 문자열 "0"과는 다르다.
console.log(1 == '1') // true
console.log(1 == true) // true
console.log('1' == true) // true
마찬가지로 1과 "1" 그리고 true도 동일한 관계를 갖는다.
타입에 엄격하지 않은 ==연산자를 대체하여 엄격한 ===연산자를 사용해 동등 비교를 한다.
명칭적 타이핑(Nominal Typing)
명칭적 타이핑(Nominal Typing)은 특정 키워드를 통하여 타입을 지정해 사용하는 방식이다.
C++이나 Java와 같은 언어에서 명칭적 타이핑(Nominal Typing)으로 타입 검사가 이루어진다.
클래스의 경우에는 extends와 같은 키워드를 이용해 서로 호환 가능함을 명시한다.
int num = 10;
char str = "a";
num = str; // ERROR!!
num = "a"; // ERROR!!
str = 10; // ERROR!!
구조적 타이핑(Structural Typing)
구조적 타이핑(Structural Typing)은 맴버에 따라 타입을 검사하는 방법이다.
명칭적 타이핑(Nominal Typing)과 반대되는 방법으로 TypeScript, Go등에서 사용한다.
구조적 타이핑(Structural Typing)은 두 데이터의 타입 구조를 비교하여 호환되는 타입인지 검사한다.
한 타입이 다른 타입이 갖는 맴버를 모두 가지고 있을 경우 두 타입은 호환되는 타입이다.
interface People {
name: string
}
let people: People
let p = { name: 'Min Su', location: 'Pangyo' }
people = p
People인터페이스는 string타입의 name을 타입 구조로 갖는다.
p라는 object변수는 string타입의 name과 location을 갖고있다.
p가 가지고 있는 데이터에는 key가 name이고 value가 string인 값이 있다.
따라서 People이 요구하는 맴버가 p에는 모두 존재하여 people에 p를 대입할 수 있다.
덕 타이핑(Duck Typing)
덕 타이핑(Duck Typing)은 객체의 변수 및 메소드 집합이 객체의 타입을 결정하는 것이다.
덕 타이핑(Duck Typing)이란 용어는 덕 테스트에서 유래했다.
어떤 새가 오리처럼 걷고, 헤엄치고, 소리를 낸다면 그 새를 오리라고 부를 것이다.
덕 타이핑(Duck Typing)은 Python, Ruby등에서 사용된다.
아래와 같이 Duck클래스와 Dog클래스를 파이썬 코드로 구현할 수 있다.
class Duck:
def __init__(self):
self.name = "오리"
def sound(self):
print("꽥꽥!")
def walk(self):
print(f"{self.name}가 걷는다.")
class Dog:
def __init__(self):
self.name = "개"
def sound(self):
print("왈왈!")
def walk(self):
print(f"{self.name}가 걷는다.")
Duck클래스와 Dog클래스 모두 sound와 walk매서드를 내부에 가지고 있다.
객체를 인자로 받고 sound, walk매서드를 내부에서 사용하는 함수를 구현해보자.
def make_sound(duck):
duck.sound()
def take_walk(dog):
dog.walk()
make_sound함수는 duck을 인자로 받고, take_walk함수는 dog를 인자로 받는다.
Duck클래스와 Dog클래스는 서로 다른 클래스이지만 같은 메서드와 필드를 갖는다.
따라서 덕 타이핑에 의해 아래와 같이 코드를 작성해 실행해도 문제가 없다.
duck = Duck()
dog = Dog()
make_sound(duck) # 꽥꽥!
make_sound(dog) # 왈왈!
take_walk(duck) # 오리가 걷는다.
take_walk(dog) # 개가 걷는다.
Duck클래스와 Dog클래스가 갖는 메서드와 필드가 모두 동일하기 때문이다.
만약 Duck클래스나 Dog클래스에 메서드가 존재하지 않을 경우 런타임 에러를 발생시킨다.
타입을 지정하면서 생기는 제약은 줄일 수 있어 유연하게 코드를 작성할 수 있다.
하지만 타입 검사를 하지 않기 때문에 오류가 발생하기 쉬우며 테스트 코드를 작성하는 것이 좋다.
목차
참고레퍼런스
'개발 공부 > JavaScript 33가지 필수지식' 카테고리의 다른 글
[JavaScript 33가지 지식]함수범위, 블록범위, 렉시컬 범위 (0) | 2022.12.01 |
---|---|
[JavaScript 33가지 지식] == vs === vs type of (0) | 2022.12.01 |
[JavaScript 33가지 지식] 값 타임(Value Type)과 참조 타입(ReferenceType) (1) | 2022.11.29 |
[JavaScript 33가지 지식] 원시자료형(Primitive Types) (0) | 2022.11.28 |
[JavaScript 33가지 지식] 호출스택(Call Stack) (0) | 2022.11.28 |