javascript 원시값과 객체의 비교

원시값과 객체의 비교

원시 타입과 객체 타입의 차이점

  1. 원시 타입의 값은 변경 불가능한 값이다. 객체 타입의 값은 변경가능한 값이다.
  2. 원시 값을 변수에 할당하면 변수에는 실제 값이 저장된다. 객체를 변수에 할당하면 변수에는 참조 값이 저장된다.
  3. 원시 값을 갖는 변수를 다른 변수에 할당하면 원본의 원시 값이 복사되어 전달된다. 이를 값에 의한 전달이라 한다. 객체를 가리키는 변수를 다른 변수에 할당하면 원본의 참조 값이 복사되어 전달된다. 이를 참조에 의한 전달이라 한다.

원시 값

변경 불가능한 값

원시타입 : 변경 불가능한 값
변경이 불가능한 값이라는 것은 변수란 값을 저장하기 위한 메모리의 공간 자체 또는 공간을 식별하기 위한 이름이고 값은 저장된 데이터이다. 즉 변경 불가능하다는 것은 변수가 아닌 값에대한 이야기이다.

변경이 불가능한것은 상수와 같은 맥락이긴 하지만 원시값은 재할당시 값이 바뀌지 않고 새로운 공간에 값을 저장하지만 상수는 재할당이 안되므로 둘의 개념이 완벽히 일치하는 것은 아니다.

1
2
3
4
5
const a = {};

a.first = 1;
// const 키워드를 사용하여 선언한 변수에 할당한 값은 변경이 불가능하다.
// 하지만 const 키워드를 사용한 변수에 할당한 객체는 변경이 가능하다.

변수에 할당한 값은 원시 값으로 한번 할당하면 그 값의 변경이 불가능하다. 변수에 값을 재할당시 기존에 값이 저장되어있던 메모리 주소에 새로운 값을 갱신하는 것이 아닌 새로운 메모리 공간에 저장하고 그 메모리 주소를 가리키게 되는데 값의 이러한 특성을 불변성이라고 한다.

문자열과 불변성

자바스크립트에서 문자열은 원시타입으로 제공된다. 문자열 타입은 원시 타입이며 변경이 불가능하다. 이것은 문자열이 생성된 이후에는 변경이 불가능하다는 것이다.

1
2
var str = 'hello';
str = 'world';

위의 코드는 str이라는 변수를 생성하고 hello라는 값을 할당하여 str이 hello가 저장된 메모리공간을 참조하게 된다. 이후 str에 world라는 값을 재할당시 str은 새로 할당한 값의 주소를 가리키게 된다.

문자열은 유사 배열 객체로도 사용이 가능하다.
유사 배열 객체란 배열처럼 인덱스로 프로퍼티에 접근이 가능하며 length프로퍼티를 가지는 객체를 의미한다.

1
2
3
4
5
var str = 'hello';

console.log(str.length); // 5

console.log(str[0]); // h

이처럼 각 인덱스로 프로퍼티에 접근이 가능하다. 하지만 문자열은 원시 값이기 때문에 프로퍼티의 값을 변경 할 수 없다. 오로지 재할당으로만 값을 변경할 수 있는것이다.

값에 의한 전달

1
2
3
4
5
6
7
8
9
10
var a = 80;
var b = a;

console.log(a);
console.log(b);

a = 100;

console.log(a);
console.log(b);

a라는 변수에 80을 할당하고 b에 a가 참조하는 값을 할당해준다. a와 b는 모두 80이라는 값을 가진 변수가 된다. 이후 a의 값을 100으로 재할당시 a는 100의 값을 가지고 b는 80값을 그대로 유지한다.
할당되는 변수의 값이 원시 값이기 때문에 새로 할당하는 모든 값들은 각각 다른 메모리 공간에 저장되며 참조하기 때문이다.
a와 b가 같은 80의 값을 가지더라도 두 변수가 가리키는 메모리의 주소는 다르다는 의미이다.

또다른 의미로는 변수에 값이 전달되는 것이 아닌 메모리 주소가 전달된다라고 볼 수도 있다.

1
2
var a = 100;
var b = a;

a에 100이라는 값을 할당하고 a는 100이 저잗되어있는 메모리 주소를 가리킨다.
b에 a가 가리키는 메모리 주소를 전달하여 b도 a가 가리키는 메모리 주소를 같이 공유한다.
이렇게 되면 두 변수의 값이 재할당 되는 시점 전까지는 두 변수는 각자의 식별자를 통해 한 곳의 메모리 주소를 가리키게 되어 값이 같다.

이처럼 값에 의한 전달도 값을 전달하는 것이 아니라 메모리 주소를 전달한다 단 전달된 메모리 주소를 통해서 메모리 공간에 접근하여 값을 참조한다.

객체

자바스크립트의 객체 관리 방식

객체는 프로퍼티 키를 인덱스로 사용하는 해시 테이블이라고 생각하면된다. 자바스크립트에서는 높은 성능을 위해 일반적인 해시테이블보다 나은 방법으로 객체를 구현해낸다.

해시테이블이란 키 값으로 데이터를 저장하는 자료구조중 하나이다.


변경 가능한 값

객체 타입의 값은 변경이 가능한 값이다.

1
2
3
var person = {
name: 'Lee',
};

객체를 변수에 할당하면 변수가 기억하는 메모리의 주소를 통해 접근하면 참조 값에 의해 객체에 접근이 가능해진다.
원시값을 할당한 변수를 참조하게 될때 메모리에 저장되어있는 참조 값을 통해 실제 객체에 접근하게 되는 것이다.

1
2
3
4
5
6
7
// 할당이 이루어 지는 시점에 객체 리터럴이 생성되고 그 결과로 객체가 생성된다.
var person = {
name: 'Lee',
};

// person 변수에 저장되어있는 참조 값으로 객체에 접근한다.
console.log(person); // { name: 'Lee' }

원시값은 재할당 외에는 변경할 수 있는 방법이 없다. 하지만 객체는 재할당없이 객체를 직접 변경할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
var person = {
name: 'Lee'
};

// 프로퍼티 값 변경
person.name = 'Kim';

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

console.log(person); // { name: 'Kim', address: 'seoul' }

객체는 메모리의 효율적인 사용을 위해 값을 변경이 가능하게 설계가 되어있다. 하지만 이러한 객체의 단점은 여러 식별자가 하나의 객체를 공유 할 수 있다는 것이다.

앝은 복사, 깊은 복사

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const _ = require('lodash');

const o = { x: { y: 1 } };
>// 얕은 복사
const c1 = { ...o };

console.log(o);
console.log(c1);
console.log(c1 === o);
console.log(c1.x === o.x);

// 깊은 복사
const c2 = _.cloneDeep(o);

console.log(o);
console.log(c2);
console.log(c2 === o);
console.log(c2.x === o.x);

실행결과

1
2
3
4
5
6
7
8
{ x: { y: 1 } }
{ x: { y: 1 } }
false
true
{ x: { y: 1 } }
{ x: { y: 1 } }
false
false

얕은 복사와 깊은 복사로 생성된 객체는 원본과는 다른 객체이다. 하지만 얕은 복사는 객체에 중첩되어있는 객체의 참조값을 복사하고 깊은 복사는 모두 복사하여 새로운 복사본을 만드는 차이점이 있다.

참조에 의한 전달

1
2
3
4
5
var person = {
name: 'Lee',
};

var copy = person;

객체를 가리키는 변수 personcopy라는 변수에 할당하면 원본의 참조값이 복사되어 전달 된다. 이를 참조에 의한 전달이라고 한다.

personcopy는 다른 메모리 주소를 가지고 있지만 동일한 참조값을 가진다. 이렇게 되면 한 곳에서 프로퍼티의 값을 추가 삭제 변경 할때 다른 곳도 영향을 받게 된다.

1
2
3
4
5
6
7
8
9
10
11
12
var person = {
name: 'Lee',
};

var copy = person;

console.log(copy); // { name: 'Lee' }

copy.name = 'Kim';
copy.address = 'seoul';

console.log(person); // { name: 'Kim', address: 'seoul' }
Author

han Ju Ryeon

Posted on

2021-09-28

Updated on

2021-12-05

Licensed under

댓글