728x90
자료형
- Number – 정수, 부동 소수점 숫자 등의 숫자를 나타낼 때 사용합니다. 정수의 한계는 ±2^53 입니다.
- bigint – 길이 제약 없이 정수를 나타낼 수 있습니다. 정수 리터럴 끝에 n을 붙이면 만들 수 있습니다.
- String – 빈 문자열이나 글자들로 이뤄진 문자열을 나타낼 때 사용합니다. 단일 문자를 나타내는 별도의 자료형은 없습니다.
- Boolean – true, false를 나타낼 때 사용합니다.
- null – null 값만을 위한 독립 자료형입니다. null은 알 수 없는 값을 나타냅니다.
- undefined – undefined 값만을 위한 독립 자료형입니다. undefined는 할당되지 않은 값을 나타냅니다.
- Object – 복잡한 데이터 구조를 표현할 때 사용합니다.
- Symbol – 객체의 고유 식별자를 만들 때 사용합니다.
느슨한 타입이란?
- 느슨한 타입(loosely typed)은 타입 없이 변수를 선언하는 것. 반면 강력한 타입(strong typing)을 사용하는 언어는 타입과 함께 변수를 선언해야만 한다.
- Javascript의 변수는 타입을 가지고 있지만 내부적으로 정해질 뿐이다. Javascript에서는 5개의 primitive type을 가지고 있는데 Number, String, Boolean, Null, Undefined 이다.
JavsScript의 형변환
- 내부적으로 타입이 관리되기 때문에, 종종 타입들이 내부적으로 바뀔 때도 있다. 타입 변환의 규칙을 아는 것은 매우 중요하다.
// 암시적 변환
7 + 7 + 7; // 21
7 + 7 + "7"; // 147
"7" + 7 + 7; // 777
// 명시적 변환
// toString(), parseInt(), etc..
- String을 만나기 전까지 정상적으로 계산이 되다가, String을 만난 이후로는 모든 숫자가 String으로 변환되고 결합된다.
- 이렇게 자바스크립트 엔전이 필요에 따라 자동으로 데이터타입을 변환시키는 것을 '암시적 변환'이라고 하며 개발자가 의도를 가지고 데이터타입을 변환시키는 것을 '명시적 변환'이라고 한다.
'=='와 '==='의 차이
- 자바스크립트에서는 엄격한 비교와 유형변환 비교를 모두 지원하므로, 어떤 연산자가 어떤 비교조건에 사용되는지 중요하다.
- '==='는 변수의 유형까지 고려하는 반면 '=='는 두 변수의 값만 비교한다.
느슨한 타입(loosely typed)의 동적(dynamic) 언어의 문제점과 보완법
- 실행 도중 예상치 못한 타입들이 변수에 들어와 타입에러를 발생할 수 있음.
- 동적타입의 언어는 런타임 시 확인할 수 밖에 없기 때문에, 코드가 길고 복잡해질 경우 타입 에러를 찾기 어려워 짐.
- 이러한 불편함을 해소하기 위해 TypeScript나 Flow 등을 사용할 수 있음.
JavaScript 객체와 불변성
- Immutability(변경불가성)은 객체가 생성된 이후 그 상태를 변경할 수 없는 디자인 패턴을 의미한다. 함수형 프로그래밍의 핵심 원리!
- 불변 객체를 사용하면 복제나 비교를 위한 조작을 단순화 할 수 있고 성능 개선에도 도움이 된다. 하지만 객체가 변경 가능한 데이터를 많이 가지고 있는 경우 오히려 부적절한 경우가 있다.
- JavaScript의 데이터 타입 중 원시 타입은 값이 변하지 않는 불변 값이고, 객체(Object)는 값이 바뀔 수 있는 변경 가능한 값이다.
var str = 'Hello';
str = 'world';
- 첫번째 줄이 실행되면 메모리에 문자열 'Hello'가 생성되고, 변수 str은 'Hello'의 메모리 주소를 가리킨다. 그리고 두번째줄이 실행되면 이전에 생성되었던 문자열 'Hello'를 수정하는 것이 아니라 새로운 문자열 'world'를 메모리에 생성하고 식별자 str은 이것을 가리킨다. 이때 문자열 'Hello'와 'world'는 모두 메모리에 존재하고 있다. 변수 str은 문자열 'Hello'를 가리키고 있다가 문자열 'world'를 가리키도록 변경되었을 뿐이다.
- 예시를 들어 slice() 메소드 같은 경우에도 변수에 저장된 문자열을 변경하는 것이 아니라, 새로운 문자열을 생성하여 반환하고 있다. 문자열은 변경할 수 없는 immutable value이기 때문이다.
var user1 = {
name: 'Lee',
address: {
city: 'Seoul'
}
};
var user2 = user1; // 변수 user2는 객체 타입이다.
user2.name = 'Kim';
console.log(user1.name); // Kim
console.log(user2.name); // Kim
- 위 코드를 보면 user2.name 값을 변경하니 user1의 값도 똑같이 변경된 것을 알 수 있다. user1와 user2는 값이 변할 수 있는 객체이며 동일한 값을 가리키는 메모리 주소(변수)이기 때문이다. Object는 값이 변할 수 있다.
- 위와 같이 객체 내부의 변화를 방지하기 위해서는 객체를 불변객체로 만들거나, 변경이 필요한 경우 객체의 방어적 복사를 통해 새로운 객체를 생성한 후 변경한다. 얕은복사가 아닌 깊은 복사를 하는 것.
얕은 복사(shallow copy) vs 깊은 복사(deep copy)
- 변경 가능한 객체의 경우 객체를 직접 대입하면 참조에 의한 할당이 이루어지므로 둘은 같은 주소를 가지고 있다. 이것이 얕은 복사이다. 때문에 객체 값의 propery를 수정하게 되면 얕은 복사가 된 객체도 함께 수정이 된다.
- 깊은 복사는 원시 값처럼 완전한 복사본을 만든다. Object.assign()이나 Spread Operation을 통해 깊은 복사를 할 수 있지만, 현재의 Depth 이상으로는 깊은 복사를 하지 않는다.
- 완벽한 깊은 복사를 하는 방법은 재귀적으로 깊은 복사를 수행(단점, Object의 Depth가 길어질수록 Time Complexity(시간복잡도)가 늘어나게 됨.), Lodash의 cloneDeep 함수 사용, JSON.parse()와 JSON.stringify()함수를 사용해야 한다.