모던 자바 스크립트 DeepDive(8)

samuel Jo·2022년 7월 21일
0

딥다이브

목록 보기
8/34

Chapter 11 원시 값과 객체의 비교

원시타입과 객체타입은 크게 세가지 측면에서 다르다.

1. 원시타입의 값 즉 원시값은 변경불가 값. 객체(참조)타입의 값, 즉객체는 변경 가능한 값

2.원시값을 변수에 할당하면(확보된 메모리공간)에는 실제 값이 저장

3. 원시값을 갖는 변수를 다른변수에 할당하면 원본의 원시값이 복사되어 전달 이를 값에 의한 전달 // 객체를 가리키는 변수를 다른 변수에 할당하면 원본의 참조 값이 복사되어 전달. 이를 참조에 의한 전달

원시 값은 변경 불가능한 값이기 때문에 값을 직접 변경할 수 없다.따라서 변수 값을 변경하기 위해 원시 값을 재할당 하면 새로운 메모리 공간을 확보하고 재할당한 값을 저장한 후, 변수가 참조하던 메모리 공간의 주소를 변경한다. 이러한 특성을 불변성 이라 한다.

문자열과 불변성

// 문자열은 0개이상의 문자로 이루어진 집합.
var str1 = '';
var str2 = 'hello';
var str = 'Hello';
str = 'world';

두번째 문이 실행되면 이전에 생성된 문자열 Hello를 수정하는 것이 아니라 새로운 문자열 world를 메모리에 생성하고, str변수는 이걸 가리킨다. 즉 str변수는 Hello를 가리키고 있다가 world를 가리키도록 변경되었을 뿐이다. (화살표를 바꿔줬다)

var str = 'string';
str[0] = 'S';

console.log(str); // string

이런경우는 어떤지 보면, 이미 생성된 문자열의 일부문자를 변경해도 반영이 되지 않는다. 이는 변경 불가능한 값이기 때문. 원시값은 어떤일이 있어도 변하지 않는다. 이뜻은 예기치 못한 변경으로 부터 자유롭고 같은 의미로는 데이터의 "신뢰성"을 보장 하는 것.

값에 의한 전달

var score = 80;

var copy = score; // 변수 score를 할당!

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

score는 변수 값 80값으로 평가되어 copy에도 80이 할당된다. 이 때, 새로운 값 80이 생성되어 copy 변수에 할당된다. 하지만 score와 copy의 값은 다른 메모리 공간에 저장된 별개의 값이다.

변수에 원시값을 갖는 변수를 할당하면 , 할당받는 변수에는 할당되는 변수의 원시값이 복사되어 전달된다 . 이를 값에 의한 전달이라 함.

var score = 80;
var copy = score;
console.log(score, copy); // 80 80
score = 100;
console.log(score, copy); // 100 80
score 와 copy 의값은 다른 메모리 공간에 저장된 별개의값이기 떄문에 score값을 변경해도 copy의 값에는 아무런 영향을 주지않음.
즉, 두 변수의 원시 값은 서로 다른 메모리 공간에 저장되 별개의 값이 되어 어느 한쪽에서 재할당을 통해 값을 변경하더라도 서로 간섭할 수 없다
var score =80;
var copy = score;
console.log(score,copy);// 80  80
console.log(score ===copy); // true

객체

객체는 프로퍼티의 갯수가 정해져 있지않고 동적으로 추가 삭제할 수 있다. 또한 프로퍼티의 값에도 제약이 없는 복합적인 자료구조,원시값과는 다른방식으로 동작 하도록 설계되어 있다.

그렇다면 변수에 객체를 할당하면 어떤일이 일어나나?

var person = {
  name: 'Lee'
};
console.log(person); // {name: "Lee"}

객체를 할당한 변수에는 생성된 객체가 실제로 저장된 메모리 공간의 주소가 저장.

이값을 참조값 이라함. 참조 값은 생성된 객체가 저장된 메모리 공간의 주소 그자체.

변수는 이 참조 값을 통해 객체에 접근 할 수 있다.

변경 가능한 값

객체는 변경 가능한 값임. 그래서

var person = {
 name: 'Lee'
};
person.name = 'Kim';
person.address = 'Seoul';
console.log(person); // {name: "Kim", address: "Seoul"}

객체를 생성하고 관리하는 것은 매우 복잡하고 비용이 많이드는일.체는 크기가 매우 클 수도 있고 그 크기 또한 일정하지도 않아서, 원시 값처럼 복사해서 생성하는 비용이 많이 들게 된다. 메모리를 효율적으로 소비하기가 힘들고 성능이 나빠지는 것이다.

그렇기 때문에 메모리를 효율적으로 사용하기 위해서 객체는 변경 가능한 값으로 설계되어 있다.

참조에 의한 전달

하지만 이렇게 설계됨에 따라 부작용이 발생하게 된다 여러개의 식별자가 하나의 객체를 공유할 수 있다는 문제.

var person = {
  name: 'Lee'
};
var copy = person;
person을 copy에 할당하면 원본의 참조 값이 복사되어 전달된다.

var person = {
name: 'Lee'
};
var copy = person;
copy.name = 'Kim';
person.address = 'Seoul';
console.log(person); // {name: 'Kim', address: 'Seoul'}
console.log(copy); // {name: 'Kim', address: 'Seoul'}

person과 copy 중 어느 한쪽에서 객체를 변경하면 서로 영향을 받는다. 한 데이터의 공유가 아닌, 똑같은 구조의 객체를 하나 더 생성하려면 어떻게 해야 할까? 이와 같은 경우에는, 깊은 복사라는 개념을 사용하면 된다.

얕은 복사(shallow copy)

const o = { x: { y: 1 } };
// 얕은 복사
const c1 = { ...o }; // 35장 "스프레드 문법" 참고
console.log(c1 === o); // false
console.log(c1.x === o.x); // true
// lodash의 cloneDeep을 사용한 깊은 복사
// "npm install lodash"로 lodash를 설치한 후, Node.js 환경에서 실행
const _ = require('lodash');
// 깊은 복사
const c2 = _.cloneDeep(o);
console.log(c2 === o); // false
console.log(c2.x === o.x); // false
var person = {
  name: 'Lee'
};
// 참조값을 복사(얕은 복사). copy와 person은 동일한 참조값을 갖는다.
var copy = person;

// copy와 person은 동일한 객체를 참조한다.
console.log(copy === person); // true

// copy를 통해 객체를 변경한다.
copy.name = 'Kim';

// person을 통해 객체를 변경한다.
person.address = 'Seoul';

// copy와 person은 동일한 객체를 가리킨다.
// 따라서 어느 한쪽에서 객체를 변경하면 서로 영향을 주고 받는다.
console.log(person); // {name: "Kim", address: "Seoul"}
console.log(copy);   // {name: "Kim", address: "Seoul"}

"값에 의한 전달"과 "참조에 의한 전달"은 식별자가 기억하는 메모리 공간에 저장되어 있는 값을 복사해서 전달한다는 면에서 동일하다.

자바스크립트에는 "참조에 의한 전달"은 존재하지 않고 "값에 의한 전달"만이 존재한다고 말할 수 있다.

자바스크립트의 동작방식을 정확히 설명하지 못한다. 정확한 용어가 존재하지 않음.

var person1 = {
  name: 'Lee'
};
var person2 = {
  name: 'Lee'
};
console.log(person1 === person2); // false
console.log(person1.name === person2.name); // true

=== 일치비교 연산자는 변수에 저장 되어 있는 값을 타입 변환하지 않고 비교.

객체리터럴은 평가될 때마다 객체를 생성. person1변수와 person2변수가 가리키는 객체는 내용은 같지만 다른메모리에 저장된 별개의 객체. person1변수와 person2변수의 참조 값은 전혀 다른값. 1은 false

BUT 프로퍼티 값을 참조하는 person1.name과 person2.name은 값으로 평가 될 수 있는 표현식 모두 원시값 'Lee'로 평가됨. 2는 true

profile
step by step

0개의 댓글