데이터 타입의 종류
- 기본형(Primitive Type)과 참조형(Reference Type)으로 구분
- 구분 기준: 값의 저장 방식과 불변성 여부
- 값의 저장 방식
- 기본형: 변수 값 자체가 저장 (변수 값이 저장된 주소값이 저장)
- 참조형: 변수 값이 아닌 메모리 상의 주소가 저장 (값이 담긴 주소값들로 이루어진 묶음을 가리키는 주소값을 복제, 힙(heap) 영역에 생성되고 메모리 주소를 통해 접근)
- 불변성 여부
- 기본형: 불변성을 띔 (변수에 새로운 값을 할당하면 이전 값을 변경 x, 새로운 값 생성)
- 참조형: 불변성을 띄지 않음 (변수는 객체를 가르키는 참조를 갖고 있으므로, 객체 내부의 속성을 수정하거나 객체를 변경할 수 있음)
- 수업에서는 구분 기준을 두 가지만 알려줬지만 찾아본 결과 다른 구분 기존도 존재
- 변수의 동작
- 기본형: 변수 간의 독립성 존재 (한 변수의 값을 변경해도 다른 변수에 영향 X)
- 참조형: 여러 변수가 동일한 객체를 참조 O (한 변수를 통해 객체를 변경하면 다른 변수에서도 변경된 객체를 참조)
- 전달방식
- 기본형: 값에 의한 전달(Call by Value) (함수로 기본형 데이터 전달할 때 해당 값이 복사되어 전달)
- 참조형: 참조에 의한 전달(Call by Reference) (함수로 참조형 데이터를 전달할 때는 해당 객체의 메모리 주소가 복사)
- 메모리 관리
- 기본형: 스택(stack) 메모리 영역에 저장, 변수의 스코프를 벗어나면 자동으로 제거
- 참조형: 객체는 힙(heap) 메모리 영역에 동적으로 생성, 가비지 컬렉터가 사용하지 않는 객체를 자동으로 회수하여 메모리를 관리
변수 선언과 데이터 할당
- 식별자, 변수
- var str -> 식별자
- test -> 변수
var str = 'test';
불변 객체
var copyObject = function (target) {
var result = {};
// for ~ in 구문을 이용하여, 객체의 모든 프로퍼티에 접근할 수 있습니다.
// 하드코딩을 하지 않아도 괜찮아요.
// 이 copyObject로 복사를 한 다음, 복사를 완료한 객체의 프로퍼티를 변경하면
// 되겠죠!?
for (var prop in target) {
result[prop] = target[prop];
}
return result;
}
- 깊은 복사
- 중첩된 객체에 대해서 완벽히 복사 O -> 재귀적 수행을 통해 가능
var copyObjectDeep = function(target) {
var result = {};
if (typeof target === 'object' && target !== null) {
for (var prop in target) {
result[prop] = copyObjectDeep(target[prop]);
}
} else {
result = target;
}
return result;
}
undefined와 null
- undefined
- 자바스크립트 엔진에서 값이 있어야 할 것 같은데 없는 경우 자동으로 부여
- 개발자가 지정할 수도 있지만 일반적으로는 부여하지 않음!
- null
- '없다'를 명시적으로 표현할 때
- 주의할 점!
- typeof null 사용 금지, 자바스크립트 유명한 버그!
실행컨텍스트
- 실행할 코드에 제공할 환경 정보들을 모아놓은 객체
- 특징 -> 자바스크립트의 특징!
- 선언된 변수를 위로 끌어올림 = 호이스팅
- 외부 환경 정보를 구성
- this 값을 설정
- 상세 설명
- 콜스택에 쌓아올림 (순서를 보장)
- 스택: LIFO (마지막으로 들어가는 게 처음으로 나옴)
- 콜스택: 함수 호출이 발생할 때마다 함수의 실행 컨텍스트를 스택 자료구조에 저장하고, 함수 실행이 완료되면 해당 컨텍스트를 제거
- 담기는 정보
- VariableEnvironment (VE)
- 현재 컨텍스트 내의 식별자 정보 (=record(environmentRecord))
- 외부 환경 정보 (=outer(outerEnvironmentReference))
- 선언 시점 LexicalEnvironment의 스냅샷(snapshot)
- LexicalEnvironment (LE)
- VariableEnvironment와 동일하지만, 변경사항을 실시간으로 반영
- 현재 컨텍스트와 관련된 코드의 식별자 정보들이 저장(수집)
- 수집 대상 정보: 함수에 지정된 매개변수 식별자, 함수 자체, var로 선언된 변수 식별자 등 -> environmentRecord
- 컨텍스트 내부를 처음부터 끝까지 순서대로 훑어가며 수집 (실행되는 것은 아님!!)
- record (environmentRecord)
- 호이스팅 (hoisting): 선언된 변수를 위로 끌어올림
- 호이스팅 순서: 변수 선언 > 함수 > 변수 값 초기화
- 함수 선언문
- function sum (x, y) { return x + y; }
- 함수 표현식
- var sum = function (x, y) { return x + y; }
- 협업을 많이 하고, 복잡한 코드, 전역 공간에서 이루어지는 코드 협업일 수록 "함수 표현식" 활용하는 습관 가지기!
- 함수 선언문을 사용하는 경우 동일한 이름의 함수를 새로 생성한 경우 모든 코드에 영향을 줄 수 있기 때문!
- outer (outerEnvironmentReference)
- 실행 컨텍스트가 생성될 때의 환경 정보를 가지고 있음
- 주요 용어
- 스코프: 식별자에 대한 유효범위
- 스코프 체인: 식별자의 유효범위를 안에서부터 바깥으로 차례로 검색해나가는 것
- outerEnvironmentReference: 스코프 체인이 가능하도록 하는 것 (외부 환경의 참조 정보)
- 정리
- 각각의 실행 컨텍스트는 LE 안에 record와 outer를 가지고 있고, outer 안에는 그 실행 컨텍스트가 선언될 당시의 LE정보가 다 들어있으니 scope chain에 의해 상위 컨텍스트의 record를 읽어올 수 있다.
- ThisBinding
- 참고
- VariableEnvironment와 LexicalEnvironment
- 공통점
- environmentRecord와 outerEnvironmentReference로 구성
- environmentRecord (record)
- 식별자 정보가 저장 (함수에 지정된 매개변수 식별자, 함수 자체, var로 선언된 변수 식별장 등)
- 호이스팅 (식별자 정보를 수집할 때 해당 개념이 발생)
- outerEnvironmentReference (outer)
- 차이점
- 스냅샷 유지여부
- VE: 스냅샷 유지 O
- LE: 스냅샷 유지 X (실시간으로 변경사항을 계속해서 반영)
- 그래서, 실행 컨텍스트를 생성할 때, VE에 정보를 먼저 담고, 이를 복사해서 LE를 생성한 후에 주로 LE를 활용!
- 순서
- 선언된 변수를 위로 끌어올림 (호이스팅)
- 외부 환경 정보 구성
- this 값을 설정
this
- 클래스로 생성한 인스턴스
- 해당 함수가 호출될 때 동적으로 바인딩되는 객체를 참조
- this를 통해 객체 내부의 속성과 메서드에 접근하거나 호출 가능
- this는 호출되는 시점에 동적으로 결정되므로, 함수를 어떻게 호출하느냐에 따라 참조하는 객체가 달라질 수 있음
- 전역 공간에서의 this: 전역 객체를 참조 (브라우저 환경: window, node 환경: global)
- 메서드로서 호출할 때 그 메서드 내부에서의 this: 해당 메서드를 호출한 객체를 참조
- 함수로서 호출할 때 그 함수 내부에서의 this: 전역 객체를 참조
- 우회하는 방법
- 변수를 활용
- 화살표 함수 (this를 바인딩하지 않는 함수, 따라서 이전의 값 (상위 값)이 유지됨)
- 콜백 함수 호출 시 그 함수 내부에서의 this: 전역 객체 참조, 단! 별로도 this를 지정한 경우 그 대상을 참조
- 생성자 함수 내부에서 호출 시: 새로 생성된 객체를 참조
- 이벤트 핸들러 내부에서 호출 시: 이벤트를 발생시킨 DOM 요소를 참조
명시적 this 바인딩
- 자동으로 부여되는 상황별 this의 규칙을 깨고 별도의 값을 저장하는 방법
- 방법
- call
- 호출 주체인 함수를 즉시 실행하는 명령
- 함수.call(객체(this로 binding), 값);
- 예시: func.call({x: 1}, 4, 5, 6);
- apply
- call과 동일! (즉시 실행)
- 함수.apply(객체, [값]);
- 유사배열객체
- 반드시 length가 필요! 없으면 유사배열로 인식하지 않음
- ES6에서 새로운 방법 제시됨, Array.from
- Array.from(객체) -> 배열이 출력된다.
- bind
- 즉시 실행하지 않음
- 목적
- 함수에 this를 미리 적용
- 부분 적용 함수 구현할 때 용이