Javascript 의 데이터 타입는 크게 두가지로 나뉜다.
기본형 (원시형)
|
참조형 ( Object )Object 의 하위 분류
|
왜 Javascript 의 숫자타입은 다른 정적언어 (Java, C 등) 과 다르게 데이터타입이 하나밖에 없을까?
(Java 의 경우 short , int , long 등 정수형타입 뿐만아니라 float 등 다양한 숫자타입이 있음)
Java와 C 같은 언어가 나왔을시기엔 메모리 용량이 부족했던 시절이였기에
타입별로 메모리에 맞는 형변환 작업을 했어야했다.
하지만 Javascript 는 과거보다 월등히 메모리용량이 커졌기때문에
상대적으로 메모리 관리에 대한 압박에서 자유로워졌다.
숫자의 경우 정수형인지 부동소수형인지를 구분하지 않고 64bit 즉 8byte 를 확보한다.
그렇다면 기본형과 참조형을 구분하는 기준은 무엇일까?
먼저 기본형 데이터는 불변성을 띄고 참조형 데이터는 가변성을 띈다.
또다른 차이점으로는 기본형과 참조형은 할당이나 연산시에 큰 차이점이 있는데
먼저 기본형은 할당/연산시에 값을 갖고있는 주솟값을 복제한다.
그리고 참조형은 값을 갖고있는 주솟값의 묶음의 주솟값을 복제한다.
먼저 변수를 선언할때 메모리상에서 어떻게 할당되는지 알아보자
var a = 'abc'
변수 : 변경가능한 데이터가 담길 수 있는 공간 // var a
식별자 : 그 변수의 이름 // a
변수 영역 | 주소 | 1001 | 1002 | 1003 | 1004 |
데이터 | 이름 : a 값 : @5002 |
데이터 영역 | 주소 | 5001 | 5002 | 5003 | 5004 |
데이터 | 'abc' |
변수영역에 빈공간(@1002)를 확보한 후, 확보한 공간의 식별자를 a로 지정한다.
데이터 영역에서 'abc' 라는 문자열이 있는지 확인후 없다면 빈공간(@5002)에 문자열 'abc' 를 저장한다.
앞서 저장한 문자열의 주소(@5002)를 @1002에 대입한다.
다른 예제 :
var a = 'abc'
a = 'abcdef'
변수 영역 | 주소 | 1001 | 1002 | 1003 | 1004 |
데이터 | 이름 : a 값 : |
데이터 영역 | 주소 | 5001 | 5002 | 5003 | 5004 |
데이터 | 'abc' | 'abcdef' |
이전과 같은 값을 할당한 후 a 에다 재할당하는 예제이다.
여기서 중요한건 기존에 'abc' 라는 값(@5002) 뒤에 'def'를 붙혀서 데이터공간을 재활용하는것이 아니라
새로운 메모리에(@5003) 새롭게 데이터를 할당한다.
기존에 있는 기본형데이터를 수정하거나 삭제하지 않고 무조건 새로 만들어 별도의 공간에 저장한다.
이러한 특징이 기본형 데이터는 불변성을 띈다고 표현한다.
왜 굳이 변수영역과 데이터영역을 나눈거지? 그냥 변수영역 값에다 바로 저장하면 되는거 아닌가?
데이터 변환을 자유롭게 할 수 있음과 동시에 메모리를 더욱 효율적으로 관리하기 위한 고민의 결과이다.
영역을 별도로 나눈 이유는 크게 두가지로 볼 수있다.
첫번째로 값 변경시 추가적인 별도 작업을 추가로 해야되기 때문이다.
자바스크립트에서 문자열은 숫자형과 다르게 특별한 규격이 없이 가변적이다.(글자당 영어 1byte, 한글 2byte)
만약 데이터영역을 나누지 않고 변수 영역에다 바로 저장을 했을때 값이 변경된다면
변경된 데이터 크기에 맞게 메모리를 늘리는 작업이 선행되어야 할것이다.
두번째로 중복된 데이터에 대한 처리 효율 때문이다.
만약 5(8byte)라는 값을 500개의 변수영역에 바로 저장했을시 (500 * 8) = 4000 byte 를 사용하게되는데
분리된 데이터영역에 5라는 값을 넣어놓고 그 주솟값(ex :2byte)만 가져가 사용하게 된다면
(500 * 2 + 8) byte 만 사용하게되므로 훨씬 효율적으로 메모리를 사용할 수 있다.
그럼 참조형데이터의 메모리 할당을 알아보자
var obj1 = {
a : 1,
b : 'bbb'
}
변수 영역 | 주소 | 1001 | 1002 | 1003 | 1004 |
데이터 | 이름 : obj1 값 : @5001 |
데이터 영역 | 주소 | 5001 | 5002 | 5003 | 5004 |
데이터 | @7103 ~ ? | 1 | 'bbb' |
객체 @5001 변수 영역 |
주소 | 7103 | 7104 | 7105 | 7106 |
데이터 | 이름 : a 값 : @5003 |
이름 : b 값 : @5004 |
앞서 봤던 원시형데이터 를 메모리에 할당 하는 예제와는 다르게 참조형데이터는
참조형데이터의 변수영역이 별도로 존재한다.
참조형데이터 변수영역에서도 마찬가지로 데이터영역의 주솟값을 가져와 값에 대입한다.
데이터영역의 저장된 값들은 모두 불변값이다.
원시형 데이터가 들어가있는 데이터와 참조형데이터의 주솟값묶음을 갖고있는
데이터들은 절대로 수정되거나 삭제되지 않는 불변값이다.
만약 객체안의 값을 바꾼다면?
var obj1 = {
a : 1,
b : 'bbb'
}
obj1.a = 2;
변수 영역 | 주소 | 1001 | 1002 | 1003 | 1004 |
데이터 | 이름 : obj1 값 : @5001 |
데이터 영역 | 주소 | 5001 | 5002 | 5003 | 5004 |
데이터 | @7103 ~ ? | 2 | 1 | 'bbb' |
객체 @5001 변수 영역 |
주소 | 7103 | 7104 | 7105 | 7106 |
데이터 | 이름 : a 값 : |
이름 : b 값 : @5004 |
객체변수영역의 값은 변경될수있다.
이러한 부분때문에 참조형 데이터는 불변하지않다 즉 가변값이다 라고 한다.
지금까진 변수에 데이터를 재할당하는 예제를 보았다
변수에 변수를 할당하는 예제를 알아보자
var obj1 = {
a : 1,
b : 'bbb'
};
var obj2 = obj1;
obj1.a = 2;
console.log(obj1 === obj2); // true
변수 obj2 에 obj1 을 할당한 후 obj1.a 의 값을 2로 바꿨다.
나는 분명 obj1의 a 의 값만 변경했지만
console.log 로 obj1 과 obj2 를 비교했을때 ture 로 같은 object 로 나온다.
변수 영역 | 주소 | 1001 | 1002 | 1003 | 1004 |
데이터 | 이름 : obj1 값 : @5001 |
이름 : obj2 값 : @5001 |
데이터 영역 | 주소 | 5001 | 5002 | 5003 | 5004 |
데이터 | @7103 ~ ? | 2 | 1 | 'bbb' |
객체 @5001 변수 영역 |
주소 | 7103 | 7104 | 7105 | 7106 |
데이터 | 이름 : a 값 : |
이름 : b 값 : @5004 |
위에서 말한 기본형과 참조형의 차이점 중 값을 갖고있는 주솟값의 묶음의 주솟값을 복제 한다의 예제이다
원시형 같은경우 데이터가 들어있는 데이터영역의 값의 주소값을 복사하지만
참조형은 저런식으로 데이터를 갖고있는 주솟값의 묶음의 주솟값(@5001)을 복사한다.
그리하여 object 의 프로퍼티 값(@7103)을 변경하게되면 같은 주소값(@5001)을 갖고있기때문에 같이변경이된다.
만약 별도의 변경되지않는 불변객체를 만들고싶다면 어떡해야할까?
얕은복사 / 깊은복사
얕은복사 : 바로 아래단계의 값만 복사한다.
깊은복사 : 내부의 모든 값들을 하나하나 찾아서 전부 복사하는 방법이다.
위와같은 예제에서 하나의 객체를 별도로 분리하고싶을때 사용하는 방법이다.
작성예정~~
undefined 와 null
Javascript 에서 없을 을 나타내는 값이다.
두 값의 의미는 같은것 같지만 미세하게 다르고 사용하는 목적도 다르다.
먼저 undefined 를 지정하는 방법은 크게 두가지이다.
명시적으로 사용자가 변수에 undefined 를 할당하는 방법과
자바스크립트 엔진이 자동으로 부여하는 경우이다.
자바스크립트 엔진이 자동으로 부여하는 경우는
사용자가 응당 어떤 값을 지정할 것이라고 예상되는 상황임에도 실제로는 그렇게 하지 않았을 때
undefined 를 반환한다.
1. 값을 대입하지 않은 변수, 즉 데이터 영역의 메모리 주소를 지정하지 않은 식별자에 접근할때
var a;
console.log(a); // undefined
2. 객체 내부의 존재하지 않는 프로퍼티에 접근하려고 할 때
var obj = { a : 1 };
console.log(obj.b) // undefined
3. return 문이 없거나 호출되지 않는 함수의 실행결과
var func = function(){};
var c = func();
console.log(c); // undefined
그럼 명시적으로 undefined 할당하는것과 자바스크립트엔진에서 자동으로 부여하는 undefined 는
무슨 차이가 있을까?
명시적으로 undefined 를 할당하게되면 그 자체로 값이 된다.
그러므로 프로퍼티나 배열의 요소는 고유의 키값(프로퍼티)이 실존하게 되고
배열을 돌릴때 순회의 대상이 될 수 있다.
반대로 자동으로 부여하는 undefined 는 프로퍼티 내지 배열의 키값(인덱스) 자체가 존재하지 않음을 의미한다.
이렇게 변수에 같은 undefined 로 할당이 되어있지만 어떻게 할당이 되었냐에 따라서 동작이 달라
혼란을 초래할수있다.
그럼 undefined 는 어떨때 써야하는거지?
코어자바스크립트 서적에서 아주 명쾌하게 해답을 주었다
그냥 명시적으로 undefined 를 할당하지마라.
자바스크립트에서 자동적으로 부여하는 undefined 만 사용하면 된다
같은 의미를 가진 null 라는 값이 별도로 있는데 굳이 undefined 를 쓸 이유가 없다고 한다.
'비어있음'을 명시적으로 나타내고 싶을 때는 undefined 가 아닌 null 을 사용하면 된다.
그러면 undefined 는 오직 '값을 대입하지 않은 변수에 접근하고자 할 때 자바스크립트 엔진이 반환해주는 값'
으로 존재할수있을것이다.
typeof null은 출력하면 object이다.
하지만 이는 여전히 원시 타입(primitive value)로, JavaScript에서는 구현 버그로 간주한다.
'Javascript' 카테고리의 다른 글
[Javascript] Symbol (0) | 2023.08.01 |
---|---|
[Javascript] Map 데이터타입 (0) | 2023.08.01 |
[Javascript] 동작 엔진 (0) | 2021.10.29 |
[Javascript] javascript study - to be modified later (0) | 2021.10.29 |
[Javascript] addEventListener vs onclick (0) | 2021.10.21 |