원시자료형(primitive data type)
유형
객체가 아니면서 메소드가 없는 string, number, boolean, symbol, bigint, null, undefined 7가지 데이터 타입 (단, typeof null === 'object')
원리
변수를 선언하고 위와 같은 자료형의 원시값을 할당하면 stack에 변수명과 원시값이 공간을 차지하게 된다.
특징
- 모든 원시자료형은 immutable하여 값이 변경될 수 없다.
문자열도 각각의 문자에 배열의 형태로 접근하여 값을 확인할 수는 있지만 read-only 성격으로 변경할 수 없는 것을 생각하면 이해하기 쉽다. 단, 변수에 원시자료형을 담고, 재할당하는 것과는 다른 것이다.
- null과 undefined를 제외한 원시자료형은 object equivalents를 갖는다.
String,Number,Boolean,BigInt,Symbol 등이 있다.
Except for null and undefined, all primitive values have object equivalents that wrap around the primitive values
- 값을 복사할때
원시자료형은 변수의 값을 복사하므로 stack에 'b'라는 이름표를 가진 공간에 1이 할당된다.
b=7로 재할당을 시켜줄 경우, stack에서 'b'를 찾아 1이 7로 바뀌게 된다.
let a = 1;
let b = a;
b=7;
console.log(a); //1
console.log(b); //7
null
null은 immutalbe하면서 메소드가 없으므로 원시자료형에 속하지만 typeof null === 'object'이다.
- 값이 비어있다
let str = 0; ---> 값이 0이다
let str; ---> 값이 정의되지 않았다
let str = null; ---> 값이 비어있다
function getVowels(str) {
const m = str.match(/[aeiou]/gi);
if (m === null) {
return 0;
}
return m.length;
}
console.log(getVowels('sky')); //0
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/null
- 변수가 어떠한 객체도 가리키고 있지 않다.
null은 존재하지 않거나, 유효하지 않은 객체나 주소를 의도적으로 가르키는 참조이며, 모든 객체는 null로부터 파생된다.
유사하게, NaN은 숫자는 아니지만 typeof NaN === 'Number'이다. 이는 null의 타입이 object인것과 마찬가지로 숫자인지 아닌지를 확인할때 숫자들과 함께 사용되므로 숫자 자료형이라고 할 수 있다.
The reasoning behind this is that null, in contrast with undefined, was (and still is) often used where objects appear. In other words, null is often used to signify an empty reference to an object. When Brendan Eich created JavaScript, he followed the same paradigm, and it made sense (arguably) to return "object". In fact, the ECMAScript specification defines null as the primitive value that represents the intentional absence of any object value (ECMA-262, 11.4.11).
https://stackoverflow.com/questions/20480729/why-does-typeofnull-return-object-but-you-cant-assign-properties-to-it/20480863#20480863
참조자료형(reference data type)
function, object, array
값을 복사할 때
참조자료형은 변수의 주소를 복사하므로 stack에 있는 'arr'과 'copied'이름표를 가진 공간에는 같은 주소값이 담겨있다. 따라서 copied를 수정하면, arr도 수정된다.
arr.slice()로 복사하여 새로운 변수 copied2에 담은 경우, copied2를 수정하면 copied2만 수정될 뿐, arr은 수정되지 않는다. 즉, 배열을 공부하면서 slice()로 복사를 한 경우, 원본을 파괴하지 않는다고 했는데 그 원리가 배열은 참조자료형이고, slice()로 복사해서 새로운 변수에 담으면 원본과 복사본의 참조주소가 다르기 때문인 것 같다.
(복사와 관련해서는 얕은 복사와 깊은 복사 게시물 참고)
let arr = [1,2,3];
let copied = arr;
let copied2 = arr.slice();
copied.push('참조주소가 같은 경우');
copied2.push('참조주소가 다른 경우');
console.log(copied); //[1,2,3,'참조주소가 같은 경우']
console.log(arr); //[1,2,3,'참조주소가 같은 경우']
console.log(copeid2); //[1,2,3,'참조주소가 다른 경우']