@ 데이터 타입의 종류(기본형과 참조형)
==> 구분 기준은 값의 저장 방식과, 불변성 여부
- 기본형(Primitive type): 값이 담긴 주소값을 바로 복제, 불변성을 띔
- 참조형(Reference type): 값이 담긴 주소값들로 이루어진 묶음을 가리키는 주소값을 복제, 불변성을 띄지 않음
@ 메모리와 데이터
- 메모리, 데이터
- 비트
1. 0과 1을 가지고 있는 메모리를 구성하기 위한 작은 조각을 의미 - 바이트
1. 비트 8개를 묶음 단위 - 메모리(memory : byte 단위로 구성
1. 모든 데이터는 byte 단위의 식별자인 메모리 주소값을 통해서 서로 구분이 된다.
2. Javascript의 메모리는 다른 언어의 여러 데이터 타입과 다르게 8byte로 이루어져 있어서 handling할 요소들이 많지 않다. 또한 메모리 이슈까지 고민할 필요가 없다.
- 비트
- 식별자, 변수
- 식별자 = 변수명
- 변수 = 데이터
@ 변수 선언과 데이터 할당
- 값을 바로 변수에 대입하지 않는 이유
- 자유로운 데이터 변환
1. 이미 입력한 문자열이 길어진다는 생각
==> 뒤에 작성된 데이터가 있다면 뒤에 데이터를 뒤로 미뤄야 한다. - 메모리의 효율적 관리
1. 똑같은 데이터를 여러번 저장해야 한다?
==> 1만개의 변수를 생성해서 모든 변수에 숫자 1을 할당한다면, 1만개의 변수 공간을 확보해야 한다.
- 자유로운 데이터 변환
@ 기본형 데이터와 참조형 데이터
- 기본형 데이터
- 상수
- 불변하다 : 데이터 영역 메모리를 변경할 수 없다.
- 참조형 데이터
- 변수
- 가변하다 : 데이터 영역 메모리를 변경할 수 있다.
- 바라보고있는 주소에 따라 값이 변경된다.
// STEP01. 쭉 선언을 먼저 해볼께요.
var a = 10; //기본형
var obj1 = { c: 10, d: 'ddd' }; //참조형
// STEP02. 복사를 수행해볼께요.
var b = a; //기본형
var obj2 = obj1; //참조형
b = 15;
obj2.c = 20;
console.log(a) // 10
console.log(b) // 15
console.log(obj1) // { c: 20, d: 'ddd' }
console.log(obj2) // { c: 20, d: 'ddd' }
@ 불변 객체
- 불변 객체의 정의
==> 객체의 속성에 접근해서 값을 변경하면 가변이 성립. But, 객체 데이터 자체를 변경하고자 한다면 기존 데이터는 변경되지 않는다. 즉, 불변하다라고 볼 수 있다. - 객체의 가변성에 따른 문제점으로 불변 객체가 필요하다.
// user 객체를 생성
var user = {
name: 'wonjang',
gender: 'male',
};
// 이름을 변경하는 함수, 'changeName'을 정의
// 입력값 : 변경대상 user 객체, 변경하고자 하는 이름
// 출력값 : 새로운 user 객체
// 특징 : 객체의 프로퍼티(속성)에 접근해서 이름을 변경 -> 가변
var changeName = function (user, newName) {
var newUser = user;
newUser.name = newName;
return newUser;
};
// 변경한 user정보를 user2 변수에 할당
// 가변이기 때문에 user1도 영향을 받게 된다.
var user2 = changeName(user, 'twojang');
// 결국 아래 로직은 skip하게 된다.
if (user !== user2) {
console.log('유저 정보가 변경되었습니다.');
}
console.log(user.name, user2.name); // twojang twojang
console.log(user === user2); // true
==> 객체의 가변성에 따른 문제점이 들어난다.
// user 객체를 생성
var user = {
name: 'wonjang',
gender: 'male',
};
// 이름을 변경하는 함수 정의
// 입력값 : 변경대상 user 객체, 변경하고자 하는 이름
// 출력값 : 새로운 user 객체
// 특징 : 객체의 프로퍼티에 접근하는 것이 아니라, 아에 새로운 객체를 반환 -> 불변
var changeName = function (user, newName) {
return {
name: newName,
gender: user.gender,
};
};
// 변경한 user정보를 user2 변수에 할당
// 불변이기 때문에 user1은 영향X
var user2 = changeName(user, 'twojang');
// 결국 아래 로직이 수행되겠네요.
if (user !== user2) {
console.log('유저 정보가 변경되었습니다.');
}
console.log(user.name, user2.name); // wonjang twojang
console.log(user === user2); // false
==> 개선을 했지만 changeName함수는 새로운 객체를 만들기 위해 변경할 필요가 없는 gender 프로퍼티를 하드코딩으로 입력했다.
==> 얕은 복사를 이용해 개선
//패턴
var copyObject = function (target) {
var result = {};
// for ~ in 구문을 이용하여, 객체의 모든 프로퍼티에 접근할 수 있다.
// 이 copyObject로 복사를 한 다음, 복사를 완료한 객체의 프로퍼티를 변경
for (var prop in target) {
result[prop] = target[prop];
}
return result;
}
//위 패턴을 예제에 적용
var user = {
name: 'wonjang',
gender: 'male',
};
var user2 = copyObject(user);
user2.name = 'twojang';
if (user !== user2) {
console.log('유저 정보가 변경되었습니다.');
}
console.log(user.name, user2.name);
console.log(user === user2);
==> 이 또한 문제점을 가지고 있다. 중복된 객체에 대해서 완벽한 복사를 진행할 수 없다. 참조형 데이터가 저장된 프로퍼티를 복할 때, 주소 값만 복사한다.
==> 이를 개선할 수 있는 방법이 깊은 복사이다. 내부의 모든 값들을 하나하나 다 찾아서 모두 복사
var user = {
name: 'wonjang',
urls: {
portfolio: 'http://github.com/abc',
blog: 'http://blog.com',
facebook: 'http://facebook.com/abc',
}
};
var user2 = copyObject(user);
user2.name = 'twojang';
// 바로 아래 단계에 대해서는 불변성을 유지하기 때문에 값이 달라진다.
console.log(user.name === user2.name); // false
// 더 깊은 단계에 대해서는 불변성을 유지하지 못하기 때문에 값이 같다.
user.urls.portfolio = 'http://portfolio.com';
console.log(user.urls.portfolio === user2.urls.portfolio); // true
// 아래 예도 같다.
user2.urls.blog = '';
console.log(user.urls.blog === user2.urls.blog); // true
==> ser.urls 프로퍼티도 불변 객체로 만들어야 한다.
var user = {
name: 'wonjang',
urls: {
portfolio: 'http://github.com/abc',
blog: 'http://blog.com',
facebook: 'http://facebook.com/abc',
}
};
// 1차 copy
var user2 = copyObject(user);
// 2차 copy
user2.urls = copyObject(user.urls);
user.urls.portfolio = 'http://portfolio.com';
console.log(user.urls.portfolio === user2.urls.portfolio);
user2.urls.blog = '';
console.log(user.urls.blog === user2.urls.blog);
==> 객체의 프로퍼티 중, 기본형 데이터는 그대로 복사 + 참조형 데이터는 다시 그 내부의 프로퍼티를 복사 ㅡ> 재귀적 수행(함수나 알고리즘이 자기 자신을 호출하여 반복적으로 실행되는 것)
var copyObjectDeep = function(target) {
var result = {};
if (typeof target === 'object' && target !== null) {
for (var prop in target) {
result[prop] = copyObjectDeep(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);
==> 이렇게 되면 깊은 복사를 완벽하게 구현 가능.
- 다른 마지막 방법으로 JSON(JavaScript Object Notation)을 이용하는 방법.
- 장점
1. JSON.stringify() 함수를 사용하여 객체를 문자열로 변환한 후, 다시 JSON.parse()함수를 사용하여 새로운 객체를 생성하기 때문에, 원본 객체와 복사본 객체가 서로 독립적으로 존재. 따라서 복사본 객체를 수정해도 원본 객체에 영향을 미치지 않는다.
2. JSON을 이용한 깊은 복사는 다른 깊은 복사 방법에 비해 코드가 간결하고 쉽게 이해할 수 있다. - 단점
1. JSON을 이용한 깊은 복사는 원본 객체가 가지고 있는 모든 정보를 복사하지 않는다. 함수나 undefined와 같은 속성 값은 복사되지 않는다.
2. JSON.stringify()함수는 순환 참조(Recursive Reference)를 지원하지 않는다. 따라서 객체 안에 객체가 중첩되어 있는 경우, 복사할 수 없다. 객체의 구조가 복잡하거나 순환 참조가 있는 경우에는 다른 깊은 복사 방법을 고려해야 한다.
- 장점
@ undefined와 null
- undefined
- 값이 있어야 할 것 같은데 없는 경우, 자동으로 부여한다.
1. 변수에 값이 지정되지 않은 경우, 데이터 영역의 메모리 주소를 지정하지 않은 식별자에 접근할 때
2. .이나 []로 접근하려 할 때, 해당 데이터가 존재하지 않는 경우
3. return 문이 없거나 호출되지 않는 함수의 실행 결과 - '없다'를 명시적으로 표현할 때는 undefined를 사용하면 안된다.
- 값이 있어야 할 것 같은데 없는 경우, 자동으로 부여한다.
- null
- '없다'를 명시적으로 표현할 때
- typeof null은 object이다. javascritp 자체 버그이므로 조심해야 한다.
'JavaScript Dev. > Javascript' 카테고리의 다른 글
12. this(정의, 활용 방법, 바인딩, call, apply, bind) (1) | 2023.10.19 |
---|---|
11. 실행 컨텍스트(스코프, 변수, 객체, 호이스팅) (0) | 2023.10.11 |
2023.04.15 - Number vs. parseInt (1) | 2023.04.15 |
2023.04.12 - <2주차 과제> (0) | 2023.04.12 |
9. Map과 Set (0) | 2023.04.10 |