데브코스의 팀원들과 js스터디를 시작했다!
2주 남짓한 시간에 맞춰 코어 자바스크립트 라는 책으로 공부하기로 했다.
하루에 1강씩, 내용을 각자 정리해와서 서로 모르는 것이나 궁금한 내용을 정리하기로 했다.
조금씩 열심히 사는 것 같아 너무 뿌듯하다.. 기분 좋군😀
이 글의 내용은 코어 자바스크립트를 보고 작성했습니다
데이터 타입에는 기본형 타입 / 참조형 타입이 있다.
number
string
boolean
null
undefined
symbol(+ES6)
...
object
Array
Function
Date
RegExp
Map (+ES6)
WeakMap (+ES6)
Set (+ES6)
WeakSet (+ES6)
...
기본형은 값이 담긴 주소값을 바로 복제하는 반면 참조형은 담긴 주솟값들로 이루어진 묶음을 가리키는 주솟값을 복제한다.
이것 때문에 기본형은 할당이나 연산 시 복제되고, 참조형은 참조되는 것으로 보여진다.
기본형은 불변성을 가진다.
var a;
a = 'abc';
는
var a = 'abc';
와 내부적으로는 같다.
변수선언을 하고 데이터를 할당할 때의 메모리 동작은 다음과 같다.
메모리에서 비어있는 공간을 확보하고, 그 공간의 이름을 'a'라고 설정한다.
이때 비어있는 공간 안에 'abc'라는 문자열이 그대로 들어갈 것 같지만, 아니다.
데이터를 저장하기 위한 별도의 메모리 공간을 다시 확보해 문자열 'abc'를 저장하고, 그 주소를 변수 영역에 저장하는 식으로 이루어진다.
a = 'def';
가 일어난다면, 'def'라는 문자열을 가지고 있는지 파악한 다음, 없으면 새로 문자열을 생성한 뒤 그 주소를 변수 a가 할당된 메모리에 다시 적는다.
이런식으로 진행되기 때문에, 데이터 영역에 적혀진 값은 가지비 컬렉팅을 당하지 않는 한 영원히 변하지 않는 것이다.
반면 참조형을 보자.
var obj1 = {
a : 1,
b : 'bbb'
}
일 때, obj1이 선언되고, 그 안의 프로퍼티들의 주소를 객체에 주소에 담는다. 데이터 영역에 저장된 값들은 모두 불변값이지만, 데이터 영역에 적혀있는 주소가 변수 영역의 주소이기 때문에, 프러퍼티는 변경 가능하다!
obj1.a = 2;
라고 할 때, 데이터 영역에서 2를 찾고, 없으니 데이터 영역에 새로운 주소를 할당해 2라는 값을 만든다. 그리고 이 주소를 가르키고 있는 변수 주소에 저장한다. 이 프로퍼티 변수의 주소는 obj1의 주소가 가지고 있다, 프로퍼티 변수의 주소 자체는 변하지 않지만, 프로퍼티 변수의 주소가 가지고 있는 실제 데이터 주소가 바뀌었기 때문에 바꿀 수 있는 것이다!
즉, 새로운 객체가 만들어진 것이 아닌 기존의 객체 내부의 값만 바뀐 것이다.
그렇다면,
var obj = {
x : 3,
arr : [3, 4, 5]
};
이건 어떨까?
이건 참조형 데이터의 프로퍼티에 다시 참조형 데이터를 할당하는 경우이다. 이런 경우 중첩 객체라고 한다.
이 경우에도 깊이가 하나 더 늘어났다고 생각하면 된다.
그렇다면 기본형 데이터와 참조형 데이터의 차이를 알아보자.
var a = 10;
var b = a;
var obj1 = {c : 10, d : 'ddd'};
var obj2 = obj1;
기본형 데이터 a, b를 보자.
먼저 a에서 할당이 이뤄지고, b에서 복사를 한다. 이때 a의 주소 값을 b에서 복사한다.
obj1도 마찬가지다. 똑같이 obj1에 저장된 주소를 obj2가 복사한다.
b = 15;
obj2.c = 20;
이렇게 값을 바꿔버린다면?
먼저 기본형 b 변수를 살펴본다면, 15를 데이터 영역에서 찾는다. 없으니 데이터 영역에 값 15를 가지는 메모리를 할당한다. b가 가지고 있는 주소를 15의 주소로 바꾼다.
이렇게 되면 a와 b는 더이상 같은 값을 가리키지 않는다.
반면,
obj2를 살펴보자.
먼저 20을 가지는 데이터 변수가 있는지 살펴보고, 없으니 데이터 영역에 값 20을 가지는 메모리를 할당한다. 그리고 변수 c가 가지고 있는 주소의 값을 20의 메모리 주소 값으로 바꿔준다.
c는 20으로 값이 바뀌었지만, obj1, 0bj2의 메모리 값은 동일하기 때문에 obj1.c의 값도 20으로 되는 것이다.
이때 아예
obj2 = {c : 20, d : 'ddd'};
라고 새로운 객체 자체를 만들어서 주면 다른 주소값으로 할당이 된다.
그런데 값으로 전달받은 객체에 변경을 가하더라도 원본 객체는 변하지 않아야 하는 경우가 종종 있기 마련이다. 이때 불변 객체가 필요하다.
이것은 별도 함수로도 구현할 수 있고, 라이브러리를 설치해 사용할 수도 있다.
얕은 복사란, 바로 아례 단계의 값까지만 복사하는 것이다. 반면 깊은 복사는 내부의 모든 값들을 하나하나 찾아 전부 복사하는 방법이다.
객체 안의 객체 안의 객체... 이런식으로 중첩 객체가 있을 때 깊은 복사가 꼭 필요하다.
자바스크립트에서 '없음'을 나타내는 두 값의 의미, 사용하는 목적이 다르다.
주로 값이 존재하지 않을 때 자바스크립트 엔진이 자동으로 부여하는 경우가 많다.
1) 값을 대입하지 않은 변수
2) 객체 내부에 존재하지 않는 프로퍼티에 접근하려고 할 때
3) return 문이 없거나 호출되지 않는 함수의 실행 결과
일 때 쓰인다.
배열을 생성하고 초기값을 주지 않으면 empty로 나온다. 이때 empty는 순회와 관련된 배열 메서드들의 순회 대상에서 제외된다.
반면 사용자 지정의 undefined로 지정한 값은 undefined지만 읽힌다!
즉, 명시적으로 지정해준 undefined는 비어있는 의미를 가지지만 존재하는 값이라는 것이다.
상당히 헷갈리기 때문에, 코드를 짤 때 되도록이면 undefined는 넣지 않는 게 좋다.
대신 null을 넣으면 된다.
null은 말 그대로 비어있는 값이라는 뜻이다. 이렇게 사용하면 undefined는 자바스크립트가 부여해준 값, null은 사용자가 빈 값이라는 의미를 쓸 때 사용하는 것이 된다!
null의 type은 Object이다.
자바스크립트의 자체 버그라는데...뭔말이지ㅠㅠ 찾아봐야겠다
=> 찾아보니 말 그대로 버그가 맞았다고 한다!!! 무슨 이유가 있어서 그런게 아니라 진짜 버그다.
typeof 연산자를 구현할 때, 실수로 null을 체크하는 항목이 누락되어있어서 그렇다.
충격이다😅
이미 수 많은 사이트들의 코드가 기존의 typeof로 작성되어 있기 때문에, 고치면 위험해서 못고친다고 한다. 그럴 수 있겠다..그래도 어이없는 실수이긴 한듯..
아무튼 그래서어떤 변수가 null인지 아닌지를 판단할 때에는 typeof대신 === null을 써주면 된다.
결론은
자바스크립트의 null은 객체가 아닌 분명한 기본타입이며, typeof를 쓰지 말고 일치 연산자를 쓰자!😊
+메모리 구조를 설명할 때 말로만 설명하다보니 가독성이 매우 떨어지는 것 같다. 다음에 여유있을 때 그림 설명도 추가할 것!