JavaScript
[모던자바스크립트] 원시값과 객체의 비교
jjin502
2022. 7. 4. 20:31
- 자바스크립트는 크게 두 타입으로 나뉜다.
- 원시 값 : 원시 타입의 값, 즉 변경 불가능한 값
- 객체 값 : 객체 타입의 값, 즉 변경 가능한 값
그렇다면 이 두 개의 차이점은 무엇인가 .. ?
- 값 저장에서 차이
- 원시 값을 변수에 할당하면 변수(확보된 메모리 공간)에는 실제 값이 저장됨.
- 반면, 객체를 변수에 할당하면 변수(확보된 메모리 공간)에는 참조 값이 저장됨.
- 값 전달에서 차이
- 값에 의한 전달 : 원시 값을 갖는 변수를 다른 변수에 할당하면, 원시 값이 복사되어 전달됨.
- 참조에 의한 전달 : 객체를 가리키는 변수를 다른 변수에 할당하면 참조 값이 복사되어 전달.
원시 값
변경 불가능한 값
- 한 번 생성된 원시 값은 읽기 전용 값으로서 변경 할 수 없다.
주의
- 변경 불가능하다는 것은 변수가 아니라 '값'이다.
- 변수와 값은 전 ~ 혀 다른 의미임을 잊지말것 !!
그렇다면 상수는 뭐죠 .. ?
// const 키워드를 사용해 선언하는 변수는 재할당 급지.
const o = {};
// const 키워드를 사용해 선언한 변수에 할당한 원시 값은 변경할 수 없음
// 하지만, const 키워드를 사용해 선언한 변수에 할당한 객체는 변경 할 수 있음
o.a = 1;
console.log(o);
문자열과 불변성
- 문자열 : 0개이상의 문자로 이뤄진 집합.
- 불변성 : 변수 값을 변경하기 위해 원시 값을 재할당하면 새로운 메모리 공간을 확보하고 재할당한 값을 저장한 후, 변수가 참조하던 메모리 공간의 주소를 변경하는 값의 특성
var str1 = ""; // 0개의 문자로 이뤄진 문자열
var str2 = "Hello"; // 5개의 문자로 이뤄진 문자열
- 1개 문자열 크기 = 2바이트
자바스크립트 특 : 개발자 편의를 생각함
- 원시 타입인 문자열 타입을 제공함 ㅎㅎ
var str = "Hello";
var str = "world";
// 값이 덮어쓰기가 되는 것이 아닌, 새로 메모리를 확보 후 가리키는 방향을 변경함.
유사 배열 객체
- 마치 배열 처럼 인덱스로 프로퍼티 값에 접근할 수 있고,length 프로퍼티를 갖는 객체
- 즉, 배열과 유사하게 각 문자에 접근할 수 있다.
// 11-4
// 문자열과 불변성
// 문자열 - 유사 배열 객체이면서 이터러블임
var str = "string";
console.log(str[0]);
console.log(str.length);
console.log(str.toUpperCase());
그런데 .. 변하지 않는다고해서 좋은게 있나요 .. ?
// 문자열은 원시값이므로 값을 변경 할 수 없다.
var str = "string";
str[0] = "S";
console.log(str);
// 불변 -> 데이터의 신뢰성 보장
- 당근 ~ 신뢰성을 보장한다구 !!
값에 의한 전달
- 변수에 원시값을 갖는 변수를 할당받는 변수에는 할당되는 변수의 원시값이 복사되어 전달됨
// 문자열은 원시값이므로 값을 변경 할 수 없다.
var sc = 80;
var copy = sc;
console.log(sc);
console.log(copy);
sc = 100;
console.log(sc);
console.log(copy);
하지만 그들의 차이는 있다 .. 그것은 바로 ..!!
var sc = 80;
var copy = sc;
console.log(sc);
console.log(copy);
console.log(sc === copy);
// sc copy 값은 같음 그러나 메모리 주소가 다름
- 그렇다 메모리 주소가 다르다
var sc = 80;
var copy = sc;
console.log(sc);
console.log(copy);
console.log(sc === copy);
// sc copy 값은 같음 그러나 메모리 주소가 다름
sc = 100;
console.log(sc, copy);
console.log(sc === copy);
// sc와 copy가 별개라는 것을 보여줌
값에 의한 전달의 비밀
엄격히 표현하자면, 메모리 주서가 전달되는 것임.
왜죠 ..?
식별자는 값이 아니라 메모리 주소를 기억하기 때문이죠 ...
// 식별자로 값을 구별해서 식별한다
// == 식별자가 기억하고 있는 메모리주소를 통해 메모리 공간에 저장된 값에 접근할 수 있다.
// == 식별자 : 메모리 주소에 붙인 이름
var sc = 80;
// 식별자 sc는 메모리 공간에 저장된 숫자 80을 식별 할 수 있음
// 11-10
var cpy = sc;
// 위 예제 경우 sc는 식별자 표현식으로서 숫자 값 80으로 평가
// 1. 새로운 80을 생성(복사)해서 메모리주소를 전달. -> 할당 시점에 두 변수가 기억하는 메모리 주소가 다름
// 2. sc변수값 80을 메모리 주소를 그대로 전달. -> 할당 시점에 두 변수가 기억하는 메모리 주소가 같음.
// 이처럼 "값의 의한 전달" 사실은 값을 전달 한 것이 아닌,
// 메모리 주소를 전달.
// 단, 전달된 메모리 주소를 통해 메모리 공간에 접근하면 값을 참조할 수 있다.
결론
두 변수의 원시 값은 서로 다른 메모리 공간에 저장된 별개의 값이 되어 어느 한 쪽에서 재할당을 통해 값을 변경하더라도 서로 간섭할 수 없다.
객체
변경 가능한 값
// 11-11
// 변경 가능한 값 == 객체(참조) 타입의 값
var person = {
name: "Sim"
};
// 참조 값 : 생성된 객체가 저장된 메모리 공간의 주소 그 자체임
// 변수는 참조값을 통해 객체에 접근할 수 있음
- 참조값 : 객체를 할당한 변수에 생성된 객체가 실제로 저장된 메모리 공간의 주소가 저장되어있는 값.
- 변수는 참조값을 통해 객체에 접근할 수 있다.
// 11-12
// 할당이 이뤄지는 시점에 객체 리터럴이 해석되고, 그 결과 객체가 생성
var person = {
name: "Sim"
};
// person변수에 저장되어 있는 참조 값으로 실제 객체에 접근한다.
// 객체 = 변경 가능한 값
// 재할당 없이 객체를 직접 변경 할 수 있음.
// 재할당 없이 CRUD 가능
console.log(person);
// {name: "Sim"}
// 11-13
// 할당이 이뤄지는 시점에 객체 리터럴이 해석되고, 그 결과 객체가 생성
var person = {
name: "Sim"
};
// 프로퍼티 값 갱신
person.name = "Lee";
// 프로퍼티 값 동적 생성
person.address = "Ulsan";
console.log(person);
주의
- 🚨원시 값과 다르게 여러 개의 식별자가 하나의 객체를 공유할 수 있음.
얕은 복사 vs 깊은 복사
// 11-14
// 얕은 복사 : 한 단계까지만 복사
// 깊은 복사 : 객체에 중첩되어있는 객체까지 모두 복사하는 것을 말함
const o = { x: { y: 1 } };
// 얕은 복사
const c1 = { ...o };
console.log(c1 === o);
console.log(c1.x === o.x);
// lodash cloneDeep을 사용한 깊은 복사
// npm install lodash 설치 후 노드 환경에서 실행
const _ = require("loadash");
// 깊은 복사
const c2 = _.cloneDeep(o);
console.log(c2 === o);
console.log(c2.x === o.x);
// 11-15
const v = 1;
// 깊은 복사
const c1 = v;
console.log(c1 === v);
const o = { x: 1 };
// 얕은 복사
const c2 = o;
console.log(c2 === o);
참조에 의한 전달
// 11-16
// 참조에 의한 전달 : 객체를 가리키는 변수를 다른 변수에 할당하면 원본의 참조값이 복사되어 전달됨
var person = {
name: "Sim"
};
// 참조 값을 복사 : 얕은 복사
var copy = person;
// 두 개의 식별자가 하나의 객체를 공유한다.
// 서로 영향을 주고 받음
// 11-17
// 참조에 의한 전달 : 객체를 가리키는 변수를 다른 변수에 할당하면 원본의 참조값이 복사되어 전달됨/
var person = {
name: "Sim"
};
// 참조 값을 복사 : 얕은 복사
var copy = person;
console.log(copy === person);
// 객체 변경
copy.name = "Kim";
// 객체 변경
person.address = "Ulsan";
console.log(person);
console.log(copy);
// 11-18
// 참조에 의한 전달 : 객체를 가리키는 변수를 다른 변수에 할당하면 원본의 참조값이 복사되어 전달됨
var person1 = {
name: "Sim"
};
var person2 = {
name: "Sim"
};
console.log(person1 === person2);
console.log(person1.name === person2.name);
결론 ...
- 원시 값과 객체 값은 확연한 차이가 있으며 헷갈려서는 안됨 !!