본문 바로가기
Front-End/JavaScript

코어 자바스크립트

by kk님 2023. 2. 9.

 

2023/03/05

02 실행 컨텍스트

1. 실행 컨텍스트

 실행 컨텍스트: 실행할 코드에 제공할 환경 정보들을 모아놓은 객체

 => 콜스택에 쌓았다가, 가장 위에 쌓여있는 컨텍스트와 관련있는 코드들을 실행

 -> 실행 컨텍스트를 생성하고 콜스택에 담는다. 그 후 실행 컨텍스트와 관련된 코드들을 순차 실행(즉, 실행 컨텍스트가 콜 스택의 맨 위에 쌓이는 순간이 곧 현재 실행할 코드에 관여하게 되는 시점)

2. VariableEnvironment

3. LexicalEnvironment

 2-3-1 environmentRecord와 호이스팅

 - 호이스팅: 식별자들을 최상단으로 끌어올림(그 뒤 실제 코드를 실행). environmentRecord의 수집 과정을 추상화한 개념

 - 함수 선언문: 전체 호이스팅

 - 함수 표현식: 선언부만 호이스팅

=> 호이스팅이 문제를 일으킬 수 있는 상황이 있다. 함수명을 중복해서 선언문으로 선언하게 되는 경우, 나중에 할당된 값이 먼저 할당한 값을 덮어 씌우게 된다.

=> 만약 표현식으로 정의했다면? 할당 시점 이후에는 새로 적용된 함수가 적용된다. 그리고 선언부만 호이스팅 되기 때문에, 해당 변수가(함수 할당되기 전) 함수인지 모르므로 에러 발생

// 선언식
console.log(sum(1,2));

var sum (a,b) { return a+b }

//호이스팅 된 코드
var sum = function sum(a,b) { return a+b }

console.log(sum(1,2));

: 선언문은 전체를 호이스팅한다. 에러 발생하지 않음

 

//표현식

// 오류 발생
console.log(sum(1,2)); 

var sum = function (a,b) { return a+b }

// 호이스팅 된 코드
var sum;
console.log(sum(1,2));

sum = function (a,b) { return a+b }

2-3-2 스코프, 스코프 체인, outerEnvironmentReference

 - 함수 스코프

 - 블록 스코프

 => 블록은 var은 적용 안됨. 함수에 의해서만 적용됨.

 => let, const는 블록 스코프, 함수 스코프 모두 적용됨

 (1) 스코프: 식별자에 대한 유효 범위

 (2) 스코프 체인: 식별자의 유효범위를 안에서부터 바깥으로 차례로 검색해나가는 것

 => 여러 스코프에서 동일한 식별자를 선언한 경우, 가장먼저 발견된 식별자에만 접근 가능.

 

순서

(1) 전역(혹은 실행) 컨텍스트가 활성화

(2) environmentRecord에 식별자를 저장

(3) outerEnvironmentReference에는 해당 함수가 선언되 당시의 LexicalEnvironment가 담긴다.

 - 전역공간에서 해당 함수가 선언됐으면 전역 컨텍스트의 LexicalEnvironment를 참조복사. { 실행 컨텍스트의 이름, { environmaneRecord 객체 } => { GLOBAL, { 식별자1, 식별자2 }

 - 만약 '함수1' 안에서 선언됐다면 '함수1'의 LexicalEnvironment가 담긴다. { '함수1', { 식별자3, 식별자4 } }

(4) 식별자1에 접근하고자 하면 활성화 상태인 함수2 컨테스트의 environmentRecord에서 식별자1을 검색.

 

- 변수 은닉화: 스코프 체인 상에 있는 변수들에 무조건 접근 가능한 것은 아니다. 여러 곳에서 선언한 경우, 스코프 체인상 첫 번째 인자부터 검색하게 되므로 거기서 식별자가 존재한다면 스코프 체인을 더 진행하지 않기 때문에 전역 공간에서 선언한 변수에 접근할 수 없다.

//실행 컨텍스트를 제외한 상위 스코프 정보들을 확인 가능
console.dir(함수)

//디버거를 이용해 스코프 체인 확인 가능
debugger;
더보기
inner만 출력
b, inner 출력

- 전역변수와 지역변수

 => 전역 변수: 전역 컨텍스트의 LexicalEnvironment에 담긴 변수

 

5. 정리

실행 컨텍스트 객체는 활성화되는 시점에 VariableEnvironment, LexicalEnvironment, ThisBinding 정보를 수집.

실행 컨텍스트를 구성할때는 VariableEnvironment, LexicalEnvironment가 동일한 내용으로 구성

하지만, LexicalEnvironment는 함수 실행 도중 변경되는 사항이 즉시 반영

VariavleEnvironment는 초기 상태를 유지

VariableEnvironment, LexicalEnvironment는 매개변수명, 변수 식별자, 선언한 함수의 함수명 등을 수집하는 environment와 바로 직전 컨텍스트의 LexicalEnvironment 정보를 참조하는 outerEnvironmentReference로 구성되어 있다.

 

(다시 단원 첫부분으로 되돌아와서, *헷갈리는 부분*)

1. ~ Environment들의 관계!

 

VariavleEnvironment

LexicalEnvironment: environmentRecord, outerEnvironmentReference 수집

 

environmentRecord: 매개변수 이름, 함수 선언, 변수명 등이 담김.

outerEnvironmentReference

 

LexicalEnvironment가 수집하는 요소들을 도식화 한다면,

스코프 체인 점검하면서, 실행 컨텍스트 잘 이해했는지 확인하기!

var a=1;
var outer = function(){
	var inner = function() {
    	console.log(a)
        var a = 3;
    };
    inner();
    console.log(a);
};
outer();
console.log(a);

(1) 전역 컨텍스트

 LexicalEnvironment
environmentRecord: a, outer
outerEnvironmentReference: 없음

(2) outer 컨텍스트

 LexicalEnvironment
environmentRecord: inner, a
outerEnvironmentReference: { [ ?GLOBAL , { a, outer } ] }

(3) inner 컨텍스트

 LexicalEnvironment
environmentRecord: a
outerEnvironmentReference: { [ outer , { inner, a } ] }

그러면, VariableEnvironment는 여기서 나오지 않았는데.. 뭘까?

=> 일단, VariableEnvironment가 먼저 생성된 뒤, LexicalEnvironment가 이를 복제한다. 그 뒤 LexicalEnvironment를 사용한다고 한다. LexicalEnvironment는 변경 사항을 실시간으로 반영한다고 하는데, 선언부가.. 변경되는 부분이 있는건가?

 

*추가적으로,

var 과 let의 차이

var: 중복 선언이 가능하다

let: 중복 선언이 불가능하다.

 

let과 const의 차이

let: 중복 할당이 가능하다

const: 중복 할당이 불가능하다

var 중복 선언
let 중복 선언

2023/02/09 (목)

03 this

this에 대한 의문과 고찰

어랏 내가 this를 설명할 수 가 있나? this가 뭐지?

전역 객체와의 관계?

화살표함수일 때, 화살표 함수가 아닐 때. 차이? 그리고 너무 헷갈린다. 왜 다른걸까?

함수일 때, 메서드일 때 어떤 때에 this 가 전역 객체가 아닌걸까?

=> 예시들이 너무 헷갈렸음

 

this는 클래스로 생성한 인스턴스 객체. 클래스에서만 사용!

- 함수와 객체(메서드) 를 구분.(하는 유일한 기능)

 

1. 상황에 따라 달라지는 this

함수를 호출할 때 결정된다. (실행 컨텍스트가 생성될 때 결정되기 때문)

 

(1) 전역 공간에서의 this: window

 - 전역 컨텍스트를 생성하는 주체가 전역 객체이기 때문

 *자바스크립트의 모든 변수는 특정 객체의 프로퍼티로서 동작한다.(LexicalEnvironment)

=> 전역변수를 선언하면 자바스크립트 엔진은 이를 전역 객체의 프로퍼티로 할당한다.

(예) var a= 1; 하게 되면, windows.a === this.a===a

 - 전역 변수로 선언한 경우 vs 전역 객체의 프로퍼티로 할당한 경우

 : 호이스팅 여부, configurable여부(변경 및 삭제 가능성)에서 차이.

 => window.c = 1; 이렇게 전역 객체의 프로퍼티로 할당한 경우에만 delete c 혹은 delete window.c 가능.

(2) 메서드로서 호출할 때 그 메서드 내부에서의 this