티스토리 뷰

프리온보딩 프론트앤드 코스 2기 TIL

4주 차 일곱 번째 수업 TIL

YG - 96년생 , 강아지 있음, 개발자 희망 2022. 2. 23. 16:46

원티드 프리온 보딩 프론트 앤드 4주 차 일곱 번째 수업  TIL (22.01.24~22.03.03)

프리온 보딩 프론트 앤드의 강사님은 위 코드의 공동 창업자&이사의 직책을 가지고 계신 김예리 님이 강의를 해주셨습니다.

 

Execution Context

실행 컨텍스트

  • JavaScript 코드가 실행되고 있는 콘텍스트(환경)를 제공하는 객체
    • 실행 콘텍스트는 실행할 코드에 제공할 환경 정보들을(변수 정보들) 모아놓는다.
    • 함수를 실행할 때마다, 그 함수에 대한 새로운 실행 콘텍스트를 생성하여 자신만의 고유한 콘테스트에서 실행된다.
  • 어떤 정보를 가지고 있을까?
    • 코드 실행하기 위한 여러 가지 정보
    • ex) 어떤 변수가 있는지, 어떤 변수를 hoisting 할지, scope는 어떻고 scope chain은 어떻고, this는 어디에 어떻게 binding 되고 등등..

“실행할 코드”와 콜 스택 (=실행스택 =Execution Stack)

콜스택

 

실행할 코드

1. 전역 코드

  • 전역 영역에 존재하는 코드는 **전역 콘텍스트**가 생성
  • 콜 스택에 전역 콘텍스트는 하나뿐.
  • 자바스크립트 파일 실행하자마자 전역 콘텍스트부터 활성화

2. 함수 코드

  • 함수 내에 존재하는 코드를 실행하기 위한 함수 콘텍스트

3. eval코드

  • eval 함수로 실행되는 코드를 위한 eval 실행 콘텍스트

콘텍스트에 담기는 정보

이런 구조의 객체

  1. VariableEnvironment: 변수 객체(Variable Object)라고도 함
  2. LexicalEnvironment
    1. Environment Record
      • 변수와 함수 선언 등을 저장
      • 코드가 실행되기 전에 정보를 모두 수집
        • 자바스크립트 엔진은 실행되기 전에 코드의 변수명을 모두 알고 있다는 것 → hoisting
        • 해당 변수가 어떤 값을 할당했는지는 관심 없다
    2. Outer
      • 다른 LexicalEnvironment를 참조하기 위함. → scope 탐색!
  3. ThisBinding
    • 현재 콘텍스트의 this가 어디를 가리키는지?

 

Hoisting

함수 선언문과 함수 표현식

함수 선언문(function declaration)

function a() {
	// 로직
}
  • function 정의만 존재하고 별도의 할당 명령이 없다.

함수 표현식(function expression)

🤔 표현식(expression)이란 자바스크립트 인터프리터가 계산하여 값을 구할 수 있는 자바스크립트 구절을 말한다. 이러한 값을 표현하는 것을 리터럴이라고 한다.

 

var a = function() {
	// 로직
}

var b = function success() {
	// 로직
}

a();
b();
success(); // error
  • function 키워드로 정의한 함수를 변수에 할당하는 것을 말한다.

 

Hoisting

  • 호이 스팅은 변수의 선언을 끌어올리는 것을 말한다.
  • 선언부는 끌어올리고, 할당은 코드가 실행되는 시점에 진행된다.
var x = 1; 
console.log(x + " " + y); // '1 undefined'
var y = 2;

아래와 같이 동작으로 작동된다

 

var x = 1; // Initialize x
var y; // Declare y
console.log(x + " " + y); // '1 undefined'
y = 2; // Initialize y

 

함수의 Hoisting

  • 함수 선언식
catName("Chloe");

function catName(name) {
  console.log("My cat's name is " + name);
}
/*
위 코드의 결과는: "My cat's name is Chloe"
*/
  • 함수 표현식
console.log(notHoisted) // undefined
notHoisted(); // TypeError: notHoisted is not a function

var notHoisted = function() {
   console.log('bar');
};

let, const의 Hoisting

  • let, const는 hoisting이 되지 않는다
console.log(x); // Uncaught ReferenceError: x is not defined
let x = 1;

Temporal Dead Zone(TDZ)

  • let, const 역시 마찬가지로 LexicalEnvironment에 변수 정보를 미리 수집한다(hoisting의 개념으로 알고 있는 동작)
  • let, const는 실행되기 전까지 액세스 할 수 없고, 이 단계(공간)를 TDZ라고 함
x = 3; // Uncaught ReferenceError: Cannot access 'x' before initialization
let x = 1;

 

Scope

  • 변수가 유효한(살아있는) 범위
var x = 'global';

function foo () {
  var x = 'function scope';
  console.log(x);  // function scope
}

foo();
console.log(x);   // global
  • 스코프가 없었다면, 코드 전체에 절대 충돌하지 않는 변수(식별자) 명을 딱 하나만 써야 한다. 모든 프로그래밍 언어에 적용되는 개념

Scope 종류

Global Scope

  • 코드 어디에서든지 참조 가능
  • var로 선언한 변수는 전역 객체에 속하게 된다.(프로퍼티가 된다)
    • client(브라우저)의 전역 객체는 window, Node.js에서는 global
var a = '안녕';

console.log(a);  // 안녕
console.log(window.a);  // 안녕

 

 

Local Scope

 

JavaScipt는 다른 언어와 달리 scope의 범위가 함수 블록 내이다. ({} 블록과 상관이 없다)

  • = 함수에 의해서만 scope 가 생성된다.

 

 

  • if (true) {
      var x = 5;
    }
    
    console.log(x);  // 5
    
    → if 문 안에 있더라도, 일반 블록이므로 x는 전역 변수가 된다
(function () {
  var x = 5;
})();

console.log(x);  // Uncaught ReferenceError: x is not defined

→ 오로지 함수만!

 

⚠️ JavaScipt에서 let, const로 변수를 선언할 때의 scope은 블록({}) 단위이다.

{ 
	let x = 1; 
}

console.log(x); //Uncaught ReferenceError: x is not defined

 

Scope Chain

  • 변수가 해당 scope에서 유효하지 않을 때, 안에서부터 바깥으로 차례로 검색해 나가는 것
function sum() {

  var a = 3
	var b = 5;

  function inner() {
    var b = 7;
		var c = 11;

    a = a + b + c;    // a = 3, b = 7, c = 11
		console.log(a);  // 21

  };

	console.log(a);  // 3
  inner();
	console.log(a);  // 21
};

sum();
console.log(a); // Uncaught ReferenceError: a is not defined

 

Closure

  • 함수를 선언할 때 만들어진 scope가 사라진 후에도 호출할 수 있는 함수
    • "함수가 선언됐을 때"가 중요.
    • scope가 끝난 외부 함수의 변수를 참조할 수 있다.
  • 풀어서
    • 어떤 함수 A에서 선언한 변수 a를 참조하는 내부 함수 B를 외부로 전달할 경우, A의 실행 콘텍스트가 종료된 이후에도 변수 a가 사라지지 않는 현상
var A = function() {
	var a = 1;

	var B = function() {
		return ++a;
	};

	**return B;**
};

var outer = A();
console.log(outer());  // 2
console.log(outer());  // 3

메모리 관리

  • JavaScript는 원래 메모리 관리에 신경 쓰지 않아도 된다. 사용하지 않는 변수는 알아서 Garbage Collector에 수집 (실행 콘텍스트를 참고하겠죠)
  • 그런데 closure에서는 의도적으로 변수를 사용하므로 메모리가 계속 소모됨
    • 만약 GC에 수집되게 하려면 null이나 undefined를 할당하면 됨

 

This

함수와 메서드

  • 함수와 메서드는 모두 function 키워드로 함수를 정의한 것을 의미합니다.
  • 그중에서도 메서드는 객체의 프로퍼티로 함수가 정의되어야 한다.
    • 여기서 중요한 건 객체가 함수를 호출해야 메서드이다.
    let user = {
    	name: 'kim',
    	underTwenty: function(age) {
    		return age < 20;
    	}
    }
    
    user.underTwenty(30); // 메서드
    
    const under20 = user.underTwenty;
    under20(15); // 객체 안에 정의된 함수라도, 이것은 메서드가 아닌 함수
    

this

  • this는 실행 콘텍스트가 생성될 때 결정된다.
    • 실행 콘텍스트는 함수를 호출할 때 생성되므로, this는 함수를 호출할 때 결정된다.
  • this가 무엇이냐고 한다면
    • this가 바라보고 있는 객체인데, 상황에 따라 대상이 달라진다.

 

this의 동작 방식

전역 공간에서 this가 바라보는 대상

  • client(브라우저)에서는 window
  • Node.js에서는 global
var a = 1;
console.log(a);
console.log(window.a);
console.log(this.a);

메서드로 호출될 때 this가 바라보는 대상 (암시적 binding)

  • 객체의 프로퍼티에 할당된 함수를 호출하면, this는 해당 객체를 바라본다
    • 물론 객체가 메서드로 호출해야 함
var name = 'lee';

var user = {
	name: 'kim',
	getName: function() {
		console.log(this.name);
	},
	age: 50,
	child: {
		age: 15,
		underTwenty: function() {
			console.log(this.age);
			return this.age < 20
		}
	}
}

user.getName();  // kim | getName 메서드는 user 객체를 바라봄
user.child.underTwenty();  // 15 | underTwenty 메서드는 child 객체를 바라봄

user.parentUnderTwenty = user.child.underTwenty;
user.parentUnderTwenty(); // 50 | parentUnderTwenty 메서드는 user 객체를 바라봄

원하는 대상으로 this binding (명시적 binding)

call

  • 함수를 호출할 때, 원하는 대상의 객체를 인자로 넘겨준다.

apply

  • call 메서드와 완전히 같은 기능이나, 호출할 함수에 인자를 배열로 넘기느냐 or not

bind

  • call과 비슷하지만, 바로 호출하는 것이 아니라 대상을 묶어놓기(binding)만 하는 것
class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    **this.handleClick = this.handleClick.bind(this);**
  }

  handleClick() {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }

  render() {
    return (
      <button **onClick={this.handleClick}**>
        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}
  • event listener는 내부적으로 this를 이벤트가 일어난 엘리먼트로 대상을 잡아놓기 때문에
  • handleClick 내부의 this가 Class를 가리키는 것이 아닌, 엘리먼트를 가르치게 됨

arrow function

  • this의 대상이 어떤 객체가 호출했느냐로 결정되지 않는다!
  • 함수 내부에 this는 없으며, scope chain의 가장 가까운 this로 대상 결정!
class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

****  }

  handleClick = () => {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }

  render() {
    return (
      <button **onClick={this.handleClick}**>
        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

 

관련 질문

  • var vs let vs const 차이
  • 답 : var는 변수 선언 후 재할당을 하여도 아무 에러가 나지 않는다. 따라서 재할당을 하면 안 되는 변수들이 있기 때문에 const와 let이 나오게 되었는데 const는 변수를 한번 할당하면 재할당이 되지 않는 것이 특징이고 let은 var와 같이 재할당이 되지만 호이 스팅 시 차이점이 있다.
  • Hoisting 이란? (var, const, let과 연관 지어서 설명)
  • 답 : var은 호이 스팅 시 선언단계와 초기화 단계가 함께 실행이 되어 선언하기 전에 호출을 하여도 undefined가 나오지만 let과 const 는 선언단계와 초기화 단계를 각각 실행하여 호이스팅 시 변수가 있다는 것은 알고 있지만 메모리 공간 확보와 변수 초기화를 하지 않고 코드를 읽기 때문에 not definded가 나온다는 차이점이 있다.
  • Closure 란?
  • 답 : 함수를 선언할 때 만들어진 변수를 내부의 또 다른 함수를 통해서 리턴 시킬 때 함수가 끝난 이후에도 선언할 때 만들어진 변수가 계속해서 남아있는 것을 뜻합니다.
  • this에 대해 설명해주세요.
    • this는 JavaScript에서 어떻게 작동하는가?
    • 답 : this를 호출한 위치에 따라 작동이 됩니다. 가장 밖에서 호출할 시 web에서는 window , nodejs에서는 global로 this의 값이 인식되고 내부 함수에서 호출 시 함수 안에서 this의 값이 결정됩니다.
    • context란 무엇인가?
    • 답 : 함수 안에서 필요한 변수 ,  어떤 변수가 있는지 , 어떤 변수를 hoisting 할 것인지, this 가 어디로 바인딩되고 있는지 등을 뜻합니다.
    • context에 따른 this의 차이는?
    • 답 :  this는 실행 콘텍스트를 가리키는 값인데  실행 콘텍스트는 실행되는 순간에 정해지기 때문에 , this의 값은 호출 시점에 따라 동적으로 변경됩니다.
    • Call, Apply, Bind 함수에 대해 설명해달라
    • 답 :  call 은 함수를 호출할 때 , 고정시킬 this를 파라미터로 넘겨줌으로써 , this값을 고정시켜 호출할 수 있습니다. 따라서 this의 값을 원하는 값으로 호출할 수 있습니다.  apply는 this와 같은 기능을 하는데  call은 단일 객체로 인자를 넘겨주고 apply는 배열로 인자를 넘겨줍니다. bind는 call, apply처럼 고정시키고 싶은 this를 인자로 넘깁니다. 차이점은 call, apply는 this를 고정시켜 함수를 호출해주는 반면 , bind는 this 가 고정된 새로운 함수를 return 해주는 기능입니다.
    • 화살표 함수와 일반 함수와의 차이
    • 답: 화살표 함수는 함수 내부에 this가 없으며 scope chain의 가장 가까운 this로 대상을 결정한다.  스코프는 실행 콘텍스트가 아닌 렉시컬 콘텍스트(실행 시점이 아닌 함수가 정의되는 시점의 콘텍스트)를 따른다. 일반 함수와는 이러한 차이점이 있다.

 

 

참고 자료 

Closure | PoiemaWeb

 

Closure | PoiemaWeb

클로저(closure)는 자바스크립트에서 중요한 개념 중 하나로 자바스크립트에 관심을 가지고 있다면 한번쯤은 들어보았을 내용이다. execution context에 대한 사전 지식이 있으면 이해하기 어렵지 않

poiemaweb.com

https://velog.io/@ginameee/%EC% 8B% A4% ED%96%89% EC% BB% A8% ED%85% 8D% EC% 8A% A4% ED% 8A% B8% EC%99%80-this

 

실행컨텍스트와 this

Javascript에서 매번 헷갈리는 execution context와 this를 정리해본다.이 둘의 관계는 한마디로 다음으로 정리할 수 있다.this는 함수가 호출되는 시점에서, 함수를 소유하고있는 context(소유자)를 가르킨

velog.io

 

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함