반응형
데이터 타입의 종류에는 이미지와 같이 참조형(Reference Type) 기본형 (Primitive Type) 으로 나뉩니다.
기본형 Type
- Number Type ex) 1, 2, 3, 4
- String Type. ex) "string"
- Boolean Type. ex) true, false
- null. ex) 값이 없다
- undefined ex) 값이 없다
- Symbol (ES6 부터 새롭게 추가된 타입)
참조형 Type
Object (객체)
- Array 배열 ex) [0, 1, 2, 3]
- Function 함수
- Date
- RegExp 정규 표현식
- Map, WeekMap
- Set, WeekSet
기본형과 참조형의 구분 기준
1. 복제의 방식
- 기본형 - 값이 담긴 주소값을 바로 복제
- 참조형 - 값이 담긴 주소값들 이루어진 묶음을 가르키는 주소값을 복제
2. 불변의 여부
데이터 타입을 이해하기 위해 필요한 배경지식
1. 메모리, 데이터
- 비트 - 0과 1을 가지고 있는 작은 메모리 조각
- 메모리 - 작은 비트들이 모인 것
- 바이트 - 비트 8개를 모은 새로운 단위
- java, c 와 다른 javascript의 메모리 관리 방식 (feat. 정수형)
- javascript의 데이터 구분 단위는?
2. 식별자, 변수
- 변수 = 데이터
- 식별자 = 변수명
ex) var testValue = 3; 이라는 변수가 있으면 "testValue 는 식별자 즉 변수명이라고 지칭하고 var testValue = 3; 자체를 변수 즉 데이터라고 지칭합니다.
현재까지 간단 요약 정리
모든 Data 는 Byte 단위의 식별자인 메모리 주소 값을 통해서 서로 구분이 된다.
3. 변수 선언과 데이터 할당
- 할당 예시
풀어 쓴 변수 할당 방식
var testValue;
testValue = "test Value!";
붙여 쓴 변수 할당 방식
var testValue = "second test Value!";
(변수영역)주소 | ... | 1002 | 1003 | 1004 | 1005 | ... |
(변수영역)데이터 | 식별자:testValue 값: @5004 |
|||||
(데이터영역)주소 | ... | 5002 | 5003 | 5004 | 5005 | ... |
(데이터영역)데이터 | "test Value!" |
왜 값을 바로 변수에 대입하지 않는 이유 (=무조건 새로 만드는 이유)
- 자유로운 데이터 변환
- 메모리의 효율적 관리 - 변수영역 데이터가 똑같은 데이터 영역 데이터를 같게 되면 5004 값을 재활용가능 해서 효율이 좋습니다.
4. 기본형 데이터와 참조형 데이터
불변값과 불변성 (feat. 가비지컬렉팅 : 변수에 값이 바뀜으로 더이상 사용하지 않는 값을 가져감)
- 변수 vs 상수 -> 변경 가능성 EX) var a = 3 변수 , const b = 7 상수
var a = "abc";
a = a + "def";
var b = 5;
var c = 5;
b = 7;
가변값과 가변성
- 참조형 데이터의 변수 할당 과정 ( 기본형 => 불변 , 참조형 => 가변 )
var obj1 = {
a: 1,
b: "bbb",
};
(변수영역)주소 | 1001 | 1002 | 1003 | 1004 |
(변수영역)데이터 | 식: obj1 / 값: @5002 | |||
(데이터영역)주소 | 5001 | 5002 | 5003 | 5004 |
(데이터영역)데이터 | @7103 ~ @7104 | 값: 1 | "bbb" |
(ojb1 별도공간)주소 | 7103 | 7104 | 7105 | 7106 |
(ojb1 별도공간)데이터 | 식: a / 값: @5003 | 식: b / 값: @5004 |
- 기본형 데이터의 변수 할당 과정과 차이점 : 객체의 변수(프로퍼티) 영역의 별도 존재 여부
- 참조형 데이터가 불변하지 않다(가변하다)라고 하는 이유
var obj1 = {
a: 1,
b: "bbb",
};
obj1.a = 2;
- 중첩객체의 할당
var obj = {
x: 2,
arr: [2, 3, 4,],
};
(변수영역)주소 | 1001 | 1002 | 1003 | 1004 | 1005 | 1006 | 1007 | ... |
(변수영역)데이터 | obj / | obj1 / @5007 | ||||||
(데이터영역)주소 | 5001 | 5002 | 5003 | 5004 | 5005 | 5006 | 5007 | 5008 |
(데이터영역)데이터 | 1 (가비지 컬렉터) 사라질 데이터 |
"bbb" | 2 | 3 | 4 | @7103 ~ @7105 | @8104 ~ @8105 | @9104 ~ @9105 |
(arr영역)주소 | 7103 | 7104 | 7105 |
(arr영역)데이터 | 0 / @ 5003 | 1 / @ 5004 | 2 / @5005 |
(obj1영역)주소 | 8104 | 8105 | 8106 | ... |
(obj1영역)데이터 | a / @5003 | b / @5002 |
(obj영역)주소 | 9104 | 9105 | 9106 | ... |
(obj영역)데이터 | x / @5003 | arr / @ 5006 |
v. obj.arr[1]의 탐색과정
vi. 참조 카운트가 0인 메모리 주소의 처리
- 참조카운트?
- 가비지컬렉터(GC, Garbage Collector)
변수 복사의 비교
// 기본형 데이터
var a = 10;
var b = a;
// 참조형 데이터
var obj1 = { c : 10, d : "ddd" };
var obj2 = obj1;
(변수영역)주소 | 1001 | 1002 | 1003 | 1004 | ... |
(변수영역)데이터 | a / @5001 | b / @5001 | obj1 / @5003 | obj2 / @5003 | |
(데이터영역)주소 | 5001 | 5002 | 5003 | 5004 | ... |
(데이터영역)데이터 | 10 | "ddd" | @7103 ~ @7104 |
(obj1영역)주소 | 7103 | 7104 | ... |
(obj1영역)데이터 | c / @5001 | d / @5002 |
// 응?
a !== b
obj1 === obj2
복사 이후 값 변경 (객체의 프로퍼티 변경)
// 기본형 데이터
var a = 10
var b = a
// 참조형 데이터
var obj1 = { c : 10, d : "ddd" }
var obj2 = obj1
b = 15
obj2.c = 20
(변수영역)주소 | 1001 | 1002 | 1003 | 1004 | 1005 | 1006 | ... |
(변수영역)데이터 | a / @5001 | b / @ 5003 | obj1 / @5005 | obj2 / @5006 | |||
(데이터영역)주소 | 5001 | 5002 | 5003 | 5004 | 5005 | 5006 | ... |
(데이터영역)데이터 | 10 | "ddd" | 15 | 20 | @7103 ~ @7104 | @8204 ~ @8205 |
(obj1영역)주소 | 7103 | 7104 | ... |
(obj1영역)데이터 | c / @5001 | d / @5002 |
(obj2영역)주소 | 8204 | 8205 | ... |
(obj2영역)데이터 | c / @5004 | d / @5002 |
5. 불변 객체
- 불변 객체란? -> 가변일 수 밖에 없는 참조형
- 불변 객체의 필요성
example 1
var user = {
name: "sangwon",
gender: "male",
}
var changeName = function (user, userName) {
var newUser = user
newUser.name = newName
return newUser
} // input : user type 객체 , 바꿀 이름 , output : 이름 바꿔서 복사한 그 객체
var user2 = changeName(user, "leo")
if (user !== user2) {
console.log("유저 정보가 변경되었습니다.")
}
console.log(user.name, user2.name)
console.log(user === user2)
example 1의 개선 version1 (새로운 객체를 반환하도록 변경!)
var user = {
name: "sangwon",
gender: "male",
}
var changeName = function (user, newName) {
return {
name: newName,
gender: user.gender,
}
}
var user2 = changeName(user, "leo")
if (user !== user2) {
console.log("유저 정보가 변경되었습니다.")
}
console.log(user.name, user2.name)
console.log(user === user2)
위 코드의 문제점은?
더 나은 방법 (얕은 복사)
- 패턴과 적용
// 이런 패턴은 어떨까요?
var copyObject = function (target) {
var result = {}
for (var prop in target) {
result[prop] = target[prop]
}
return result
} // 기능 Good, 코드 Good
// 위 패턴을 우리 예제에 적용해봅시다.
var user = {
name: "sangwon",
gender: "male",
}
var user2 = copyObject(user)
user2.name = "leo"
if (user !== user2) {
console.log("유저 정보가 변경되었습니다.")
}
console.log(user.name, user2.name)
console.log(user === user2)
이 패턴도 문제가 있을까요?
얕은 복사 vs 깊은 복사
- 얕은 복사 : 바로 아래 단계의 값만 복사 (위의 예제) -> 문제점 : 중첩된 객체의 경우 참조형 데이터가 저장된 프로퍼티를 복사할 때, 주소값만 복사
- 깊은 복사 : 내부의 모든 값들을 하나하나 다 찾아서 모두 복사하는 방법
- 중첩된 객체에 대한 얕은 복사 살펴보기
var user = {
name: "sangwon",
urls: {
portpolio: "http://github.com/abc",
blog: "http://blog.com",
facebook: "http://facebook.com/abc",
}
}
var user2 = copyObject(user)
user2.name = "leo"
console.log(user.name === user2.name)
user.urls.portpolio = "http://portpolio.com"
console.log(user.urls.portfolio === user2.urls.portfolio)
user2.urls.blog = ""
console.log(user.urls.blog === user2.urls.blog)
위의 예시는 문제 여지가 있어요 user.urls 프로퍼티도 불변 객체로 만들어야 해요.
중첩된 객체에 대한 깊은 복사 살펴보기
var user = {
name: "sangwon",
urls: {
portpolio: "http://github.com/abc",
blog: "http://blog.com",
facebook: "http://facebook.com/abc",
}
}
var user2 = copyObject(user)
user2.urls = copyObject(user.urls)
user.urls.portpolio = "http://portpolio.com"
console.log(user.urls.portfolio === user2.urls.portfolio)
user2.urls.blog = ""
console.log(user.urls.blog === user2.urls.blog)
결론 : 객체의 프로퍼티 중, 기본형 데이터는 그대로 복사 + 참조형 데이터는 다시 그 내부의 프로퍼티를 복사 => 재귀적 수행!
[결론]을 적용한 코드 -> 완벽히 다른 객체를 반환하네요.
var copyObjectDeep = fucntion(target) {
var result = {}
if (typeof target === "object" && target !== null) {
for (var prop in target) {
result[prop] = copyObjcetDeep(target[prop])
}
} else {
result = target
}
return result
}
// 결과 확인
var obj = {
a: 1,
b: {
c: null,
d:[1, 2],
}
}
var obj2 = copyObjectDeep(obj)
obj2.a = 3
obj2.b.c = 4
obj2.b.d[1] = 3
console.log(obj)
console.log(obj2)
더 쉬운 방법은 없나요?
- J...son..?
6. undefined와 null에 대해서 : 둘 다 없음을 의미함
undefined
i. 사용자 지정
ii. 자바스크립트 엔지에서 자동 부여
- 변수에 값이 지정되지 않은 경우, 데이터 영역의 메모리 주소를 지정하지 않은 식별자에 접근할 때
- .이나 []로 접근하려 할 때, 해당 데이터가 존재하지 않는 경우
- return 문이 없거나 호출되지 않는 함수의 실행 결과
var a
console.log(a) // undefined
var obj = { a : 1 }
console.log(obj.a) // 1
console.log(obj.b) // undefined
// console.log(b) // 참조 오류
var func = function() { }
var c = func()
console.log(c) // undefined
iii. 비어있는 요소와 undefined에 대해
/** 비어있는 요소와, undefined를 할당한 요소는 다른거에요! */
var arr1 = []
arr1.length = 3
console.log(arr1) // [ 3empty items ]
var arr2 = new Array(3)
console.log(arr2) // [ 3empty items ]
var arr3 = [undefined, undefined, undefined]
console.log(arr3) // [undefined, undefined, undefined]
var arr1 = [undefined, 1]
var arr2 = []
arr2[1] = 1
// forEach
arr1.forEach(function(v, i) { console.log(v, i) )
arr2.forEach(function(v, i) { console.log(v, i) )
// map
arr1.map(function(v, i) { reuturn v + i } )
arr2.map(function(v, i) { reuturn v + i } )
// filter
arr1.filter(function(v) { return !v })
arr2.filter(function(v) { return !v })
//reduce
arr1.reduce(fucntion(p, c, i) { return p + c + i }, "")
arr2.reduce(fucntion(p, c, i) { return p + c + i }, "")
iv. 2가지 역할을 가진 undefined, 헷갈리고 위험하다!
- 지금 undefined로 나오는 이 변수가, 필요에 의해 할당한건지 자바스크립트 엔진이 반환한건지 어떻게 알죠? → 구분할 수 없어요
- ‘없다’를 명시적으로 표현할 때는 undefined를 사용하지 맙시다!
null
- 용도 : ‘없다’를 명시적으로 표현할 때
- 주의 : typeof null
var n = null;
console.log(typeof n);
//동등연산자(equality operator)
console.log(n == undefined);
console.log(n == null);
//일치연산자(identity operator)
console.log(n === undefined);
console.log(n === null);
7. 마무리
- 자바스크립트의 데이터 타입 : 기본형(불변값), 참조형(가변값)
- 변수 : 변경 가능한 데이터가 담기는 공간
- 식별자 : 변수의 이름
- 기본형 데이터와 참조형 데이터는 변수 할당 과정에서 차이가 있음
- 참조형 데이터를 가변으로 여겨야 하는 상황임에도, 이를 불변값으로 사용하는 방법 ( 깊은 복사, 라이브러리)
- 없음 : undefined, null
반응형
'JavaScript' 카테고리의 다른 글
[JS] 콜백함수 정리 (0) | 2022.12.01 |
---|---|
[JS] this 에 대한 모든 것 (0) | 2022.12.01 |
[JS] 실행 컨텍스트란? (Execution Context) (0) | 2022.11.30 |
[JS] Class vs Object 객체지향 언어 클래스 정리 (0) | 2022.10.10 |
[JS] 호이스팅(Hoisting) 은 무엇? (0) | 2022.10.05 |