Chap11. 원시 값과 객체의 비교

Muru·2023년 10월 26일
post-thumbnail

자바스크립트에서 제공하는 7가지 데이터 타입이 있다고 했다.
이 7가지 데이터 타입은 크게 두가지 타입으로 구분이 가능하다.

원시 타입 => 숫자, 문자열, 불리언, null, undefined, 심벌 타입
객체 타입 => 객체 (객체, 함수, 배열)

도대체 왜 구분하는것일까??
원시 타입과 객체타입은 크게 세가지 측면에서 다르다.

  1. 원시 값은 변경 불가능한 값이다.
    < = > 객체(참조) 타입의 값, 즉 객체 는 변경 가능한 값이다.
  2. 원시 값을 변수에 할당하면 변수(확보된 메모리공간)에 실제 값 저장한다.
    < = > 객체를 변수에 할당하면 변수(확보된 메모리공간)에는 참조 값을 저장한다.
  3. 원시 값을 갖는 변수를 다른 변수에 할당하면 원본의 원시 값이 복사되어 전달된다. 이를 값에 의한 전달이라 함.
    < = >객체를 가리키는 변수를 다른 변수에 할당하면 원본의 참조 값이 복사되 어 전달된다. 이를 참조에 의한 전달이라 한다.

11.1 : 원시 값

11.1.1 : 변경 불가능한 값

원시 타입의 값 : 원시 값은 변경 불가능한 값. 한번 생성된 값은 읽기 전용 값으로서 변경할 수 없다.

이때 변수와 값을 헷갈리지 않도록한다.
변수 => 하나의 값을 저장하기 위해 확보한 메모리 공간을 식별하기위해 붙인이름
값 => 변수에 저장된 데이터로서 표현식이 평가되어 생성된 결과.

즉 변경 불가능하다는 것은 변수가 아니라 값에 대한 진술이다.

“원시 값은 변경 불가능하다“는 원시 값 자체를 변경할 수 없다는것이지, 변수 값을 변경할 수 없는 것이 아니다.
변수는 언제든지 재할당을 통해 변수 값을 변경할수 있다.
원시 값은 변경 불가능하다 라는것은 데이터의 신뢰성을 보장하는 의미이다.
불변성을 갖는 원시 값을 할당한 변수는 재할당 이외에 변수 값을 변경할 수 있는 방법이 없다.

만약에 변수의 재할당 이외에 원시 값인 변수 값을 변경할수 있다면 ??
=> 값의 변경, 즉 상태 변경을 추적하기 어렵게 만든다.

11.1.2 : 문자열과 불변성

C에서는 하나의 문자를 위한 데이터타입(char)만 있을 뿐 문자열 타입이 존재하지 않음.

자바에서는 문자열을 String 객체로 처리한다.

자바스크립트는 개발자의 편의를 위해 원시 타입인 문자열 타입 제공한다.
앞서 공부하면서 문자열도 원시타입이라고 했다. 즉, 문자열도 생성된 이후로는 변경 할수 없음을 의미한다.

var str ='hello';
str = 'world';

첫 번째 문이 실행되면 문자열 'hello'가 생성된다.
식별자 str은 'hello'가 저장된 메모리 공간의 첫 번째 메모리 셀을 가리킨다.
두 번째 문이 실행되면 새로운 문자열 'world'가 메모리에 생성하고 식별자 str은 이것을 가리킨다.
'hello'와 world'는 모두 메모리에 존재하지만 가리키는 것이 변경된 것이다.

문자열의 한 문자를 변경해볼 수 있을까?
문자열은 이터러블이고 배열과 유사하게 각 문자에 접근할 수 있다.

var str = 'string';
str[0] = 'S';
console.log(str); // 그대로  "string"의 결과를 얻는다 

문자열은 유사 배열이므로 배열과 유사하게 인덱스를 사용해 문자접근이 가능하다. 하지만 문자열은 원시 값이므로 변경할 수 없다. 참고로 에러는 발생하지않는다.

  • 유사 배열 객체란?
    유사 배열 객체 : 마치 배열처럼 인덱스로 프로퍼티 값에 접근 가능하고
    length 프로퍼티를 갖는 객체를 말함. 그래서 for 문으로 순회도 가능하다.
var str = 'string';
for(var i=0; i<str.length; i++){
    console.log(`${[i]} = ${str[i]}`)
}
result :
0 = s
1 = t
2 = r
3 = i
4 = n
5 = g

11.1.3 : 값에 의한 전달

var scroe = 80;
var copy = score;

console.log(score); 	// 80
console.log(copy); 		// 80

위 코드처럼 변수에 변수를 할당했을 때 무엇이 어떻게 전달되는가?
변수에 원시 값을 갖는 변수를 할당하면 할당받는 변수에는 할당되는 변수의 원시 값이 복사되어 전달된다.

이 말을 다시 풀어보자면..

할당받는 변수(copy)는 할당되는 원시값(score)에 의해 원시 값(80)이 복사되어 전달된다.

score 변수와 copy변수는 숫자 값 80을 동일하게 갖는다는 점에서는 공통점이지만
score 변수와 copy 변수의 값 80은 각각 다른 메모리 공간에 저장된 별개값이다

var scroe = 80;
var copy = score;

console.log(score,copy); // 80
console.log(score === copy ); // 80

위의 코드만 보고 얼핏보면 copy는 score에 영향을 받는 유기적인 관계라고 생각할 수 있다. 하지만 score 변수와 copy 변수의 값 80은 다른 메모리 공간에 저장된 별개의 값이라는 것에 주의하자.
따라서 score 변수의 값을 변경해도 copy 변수의 값에는 영향을 주지못한다.

var score = 80;
var copy = score;
console.log(score, copy);		// 80, 80

var score = 100;
console.log(score, copy)		// 100, 80

“값에 의한 전달”이라는 용어는 자바스크립트를 위한 용어가 아니긴하다.
엄격하게 표현하면 변수에는 값이 전달되는 것이 아니라 메모리 주소가 전달되기 때문다. 이는 변수와 같은 식별자는 값이 아니라 메모리 주소를 기억하기 때문이다.

“값에 의한 전달”도 사실은 값을 전달하는 것이 아니라 메모리 주소를 전달한다. 단, 전달된 메모리 주소를 통해 메모리 공간에 접근하면 값을 참조할 수 있다.

var score = 80;
var copy = score;

/*
score 변수 : copy 변수야 내가 가리키고 있는 80의 값에 대한 메모리 주소를 
너에게 전달 할게.
copy 변수 : 너가 준 이 메모리 주소에대한 값을  새로운 메모리 공간에 값을 할당할게.
*/

score = 100;
/*
score 변수 : 내 80(값)에 대한 집(메모리주소)은 떠나고
100(값)을 위한 집(메모리주소)으로 떠날게.
*/



11.2 : 객체

객체는 프로퍼티의 개수가 정해져 있지 않다.
동적으로 추가되고 삭제할 수도 있다.
프로퍼티의 값에도 제약이 없다.
따라서 객체는 원시 값과 같이 확보해야 할 메모리 공간의 크기를 사전에 정해 둘 수 없다.

11.2.1 : 변경 가능한 값

객체(참조) 타입의 값, 즉 객체는 변경 가능한 값 이다.
다음과 같이 변수에 객체를 할당하면 어떤 일이 일어날지 살펴보도록 하자.

var person = {
   name : 'lee'
};

원시 값을 할당한 변수는 메모리 공간에 접근하면 원시 값에 접근하지만
객체를 할당한 변수는 메모리 공간에 접근하면 참조 값에 접근한다.

  • 참조 값 : 생성된 객체가 저장된 메모리 공간의 주소 그 자체.

person 변수에 저장되어 있는 메모리 값(0x000000F2)으로 참조 값인
실제 객체(0x00001332)인 실제 객체에 접근한다.

즉 person 변수는 객체 { name : 'lee' }를 가리키고(참조하고)있다.
원시 값은 변경 불가능한 값이므로 원시 값을 갖는 변수의 값을 변경하려면 재할당 외에는 방법이 없었지만, 객체는 재할당 없이 직접 변경 가능하다.
( ex : 프로퍼티 추가, 갱신, 삭제 )

var person = {
   name : 'lee'
};

// 프로퍼티 값 갱신
person.name = 'Kim';

// 프로퍼티 동적 생성
person.address = 'Seoul';

console.log(person); 
result:
{name : "Kim", address: "Seoul"}

객체는 변경 가능한 값이므로 메모리 저장된 객체를 직접 수정 가능.
객체를 할당한 변수에 재할당을 하지 않았으므로 객체를 할당한 변수의 참조 값(0x00001332)은 변경 되지 않는다.

다음과 같은 코드로 변수에 재할당을 한다면 당연하게 참조값은 변경된다.

var people = {
    name : "lee"
}

people = 5;

console.log(people);

왜 이런 설계를 했을까???

메모리 사용의 효율성과 성능을 위한 설계라고 볼 수있다.
구조적 단점에 따른 부작용 : 여러개의 식별자가 하나의 객체를 공유 가능성 존재

11.2.2 : 참조에 의한 전달

여러개의 식별자가 하나의 객체를 공유할 수 있다는게 무슨말일까?

var person = {
   name : 'lee'
};
var copy = person;

copy변수가 복사되어 할당되기전

copy변수가 복사되어 할당된 후

원본 person을 사본 copy에 할당하면 원본 person은 참조 값을 복사해서 copy에 저장한다. 메모리 주소는 다르지만 동일한 참조 값을 갖는다.

즉 person과 사본 copy는 모두 동일한 객체를 가리킨다.
이것은 두 개의 식별자가 하나의 객체를 공유한다는 것을 의미한다.

var people = {
    name : "lee"
}
copyPeople = people;
console.log(`저의 이름은${people.name} 입니다 `);   // 저의 이름은lee 입니다 
copyPeople.name = "Kim" // 사본을 통한 프로퍼티 변경
console.log(`저의 이름은${people.name} 입니다 `);   // 저의 이름은Kim 입니다 

결국 원본 또는 사본 중 어느 한쪽에서 객체를 변경하면 서로 영향을 받게된다.
“ 값에 의한 전달 ” 과 “ 참조에 의한 전달 ” 은
식별자가 기억하고있는 메모리 공간에 저장되어 있는 값을 복사해서 전달한다는 면에서는 동일하다.
다만, 변수에 저장되어 있는 값이 원시 값이냐 참조 값이냐의 차이만 존재한다.
따라서 “ 참조에 의한 전달 ” 은 존재하지 않고 “ 값에 의한 전달 ” 만 존재한다고 말할 수 있겠다.

하지만 이 같은 동작 방식을 설명하는 정확한 용어가 존재하지 않음.
이런 이유로 “공유에 의한 전달” 이라고 표현 하는경우도 있지만
이 용어 또한 자바스크립트의 공식적인 용어는 아니다.

공부의 목적을 위해 값의 종류가 원시값인지, 참조값인지 구별해서 강조하는의미로
“값에 의한 전달”과 “참조에 의한 전달”로 구분하여 부르기로한다.

다음 실행 결과를 예측해보자.

var perosn 1 = {
   name : 'lee'
};

var person 2 = {
   name : 'lee'
};

 console.log(person1 === person2);				// 1번 Question ??
 console.log(person1.name === person2.name);	// 2번 Question ??

=== 일치 비교 연산자는 변수에 저장되어 있는 값을 타입 변환하지 않고 비교한다.
원시 값을 할당한 변수 비교시 원시 값을 비교한다.
객체를 할당한 변수를 비교하면 참조 값을 비교한다.

1번의 답은 false다.
person1의 참조값은 0x00001332
person2의 참조값은 0x00001334
이므로 다른 메모리에 각각 저장된 별개의 객체라서 false

2번의 답은 true다.
프로퍼티 값을 참조하는 person1.name 과 person2.name은 값으로
평가 될 수 있는 표현식이고 ‘lee'로 같으므로 true

profile
Developer

0개의 댓글