TIL_원시타입 객체 타입

자바스크립트에서는 어떤 값에 대한 타입을 크게 두가지로 분류할 수 있는데 원시값, 객체 or 참조 값으로 분류할 수 있다.

원시타입

  • boolean
  • number
  • string
  • undefined
  • null
  • Symbol

객체타입

  • object
  • array
  • function (객체는 맞지만 여기선 등장하지않음)

원시타입

  • 변경불가능한 값
  • 변수에 실제 값이 저장
  • 복사할경우 값이 복사되어 전달

일단 첫번째부터 이해가 안갈수도있다.

var age = 18;
age = 30;

let name = 'kang';
name = 'kim';

변경 불가능한 값
변수에 대입해놓고 보면 다른값으로 변경이 가능한데 변경 불가능한값이라고 말한다. 일단 여기서 중요한 개념은 변수를 선언하고 값을 할당하면 원시값에 해당하는 값들은 고정된 크기를갖고 스택메모리에 저장이되고 그 메모리주소를 변수가 갖게된다.

그리고 해당 변수에 다른값을 재할당할때 일어나는 동작은 다시 새로운 메모리영역을 확보하고 그곳에 새로 할당한 값 30을 저장하고 변수는 30이 저장된 메모리주소를 저장하게된다.

0x00001111 메모리 주소에 18
0x00000123 메모리주소에 30

즉 메모리영역 어딘가에 18이란 값은 아직 살아있고 30이 저장된 메모리주소를 변수가 바라보고있다 라고 볼 수 있다.

변수에 실제 값이 저장
정확히 말하자면 변수가 확보한 메모리영역에 실제값이 저장되어있다는 소리이다. 이게 무슨소리인지 정확히 알려면 객체가 어떤방식으로 저장되고 참조되는지 알아야 비로소 이해할 수 있는 부분이기도하다.

복사할 경우 값이 복사되어 전달

var a = 13; // 메모리영역 어딘가에 13을 저장하고 그 메모리 주소에 a 라는 이름을 지어줌
var b = a; // 13이 저장된 메모리 주소에 b라는 이름도 붙여줌
console.log(a === b) //true

원시값을 갖는 변수를 다른 변수에 할당하면 값이 복사되어 전달되는데 이걸 값에의한 전달이라고 한다.

var a = 13;
var b = a;

console.log(a) // 13
console.log(b) // 13

a = 30; // 새로운 메모리영역을 확보하고 30을 저장 그 메모리 주소를 a 가 바라보게함

console.log(a) // 30
console.log(b) // 13

자바스크립트의 표준을 정하고있는 ECMAScript 에서 변수를통해 메모리를 어떻게 관리해야하는지 명확하게 정의되어있지 않기에 값이 복사되는 과정에 대해서 브라우저마다 다르게 동작될 수 있는 부분이 있다. 위의 설명은 파이썬의 동작과 유사한설명이고 MDN 에서 설명하는 다른 방식이 존재한다.

var a = 13; // 메모리영역 어딘가에 13을 저장하고 그 메모리 주소에 a 라는 이름을 지어줌
var b = a; // 새로운 메모리영역에 13값을 저장 그 메모리주소에 b라고 이름을 지어줌

console.log(a) // 13
console.log(b) // 13
console.log(a === b) // 메모리주소가 아닌 값 자체를 비교 true

a = 30; // 메모리영역이 다르기때문에 기존 변수의 원시값을 변경해도 복사된 변수에는 영향을 끼치지않는다.

console.log(a) // 30
console.log(b) // 13

위의 설명에서는 서로 기존 변수와 값이 복사된 변수가 같은 메모리주소를 갖는것이 아닌 서로 다른 메모리주소를 갖고 값만 복사되어 서로 다른 영역에 존재한다는것이다. 나는 변수는 값이아니라 메모리주소를 갖는다고 알고있어서 사실 비교연산할때 메모리주소를 같다 라고 보는게 아닌가 라고 생각했었는데 위의 결과대로라면 비교할때는 값 자체를 비교한다고 볼 수 있을것같다.

어쨋든 두경우 다 원시값은 재할당이 발생할때마다 서로다른 메모리영역에 저장되기때문에 복사된 변수에 대해서 간섭이 불가능하고 서로 다른 값을 가진채로 유지 할 수 있다.

객체타입

  • 객체는 변경가능한 값
  • 객체를 변수에 할당하면 변수에는 참조값이 저장
  • 복사를 할경우 원본의 참조값이 복사되어 전달 (참조에 의한 전달)

객체는 변경가능한 값
객체는 프로퍼티수가 정해져있지 않고 동적으로 추가되고 삭제를 할 수 있다. 또한 프로퍼티값에도 제약이 없기때문에 원시값처럼 사전에 확보해야할 메모리의 크기를 지정할 수 없다.

원시값은 스택메모리에저장, 참조값은 힙 메모리에 저장

var person = {
	name: 'kang',
  	age: 18,
}
console.log(person.name) // kang
console.log(person.age) // 18

person.name = 'kim';
person.job = 'programmer';

console.log(person) //{name: 'kim', age: 18, job: 'programmer'}
console.log(person.name) // kim
console.log(person.job) // programmer

객체를 변수에 할당하면 변수에는 참조값이 저장

하나씩 살펴보자면

var person = {
	name: 'kang',
  	age: 18,
}

자바스크립트에서는 원시값을 제외한 객체에 해당하는 값들은 힙메모리에 저장합니다. 그럼 힙메모리에 저장된값이 갖고있는 메모리주소가 있을건데 그 메모리주소를 스택메모리영역에 저장하고 그 메모리 주소를 담고있는 스택메모리의 주소를 person 은 갖게됩니다.

person -> 스택메모리주소 -> 힙메모리주소 -> {name: 'kang', age: 18}

여기서 person 이 저장하고있는 스택메모리주소는 힙메모리주소를 참조로 갖고있기때문에 해당 객체값을 참조값이라고부른다.

힙 메모리영역은 동적인 할당이 가능한영역으로 새로운 메모리주소의 할당없이 객체에 값을 추가, 삭제 등 변경이 가능하다.

복사를 할경우 원본의 참조값이 복사되어 전달 (참조에 의한 전달)

var person = {
	name: 'kang',
  	age: 18,
}

// 얕은복사
var person2 = person // 동일한 힙 메모리 주소를 참조
person2.name = 'kim'

console.log(person === person2) // true
console.log(person.name) // kim
console.log(person2.name) // kim

자바스크립트의 객체는 복사할경우 참조된 메모리주소가 전달되므로 복사를하더라도 객체값의 불변성이 지켜지지않는다. 따라서 객체를 공유하는 상태가되기때문에 값의 변경이 있을경우 그 값의 변동까지 공유하게된다.

즉 스택메모리영역에서는 새로운 메모리영역을 할당하겠지만 참조하고있는 힙메모리주소는 동일하다고 볼 수 있다.

객체의 복사

원시타입처럼 객체를 복사하게되면 복사를하는것이 아닌 동일한 영역을 공유하게되기때문에 원본값까지 수정이 되어버리는 상황이 발생하는데 이를 방지하고 제대로 값을 복사할 수 있는 방법이 있다.

  • Object.assign()
  • Object.freeze()
  • 전개연산자 사용 {...object}

  • JSON 사용 JSON.parse(JSON.stringify(obj))
  • lodash 에 cloneDeep
  • Immutable.js
  • 재귀

전자의 세종류는 얕은복사이고 밑에 네종류는 깊은복사가 가능한 방법이다. 얕은복사와 깊은복사의 차이는 객체는 프로퍼티값으로 또 객체를 가질 수 있다. 때문에 중첩 객체를 사용할 일이 많은데 얕은복사는 중첩되는 객체의 복사까지는 불가능하다. 그러나 깊은복사방식을 사용하면 중첩되는 객체까지의 복사도 가능하다.

좋은 웹페이지 즐겨찾기