JS 3주차 정리 :: 호이스팅 | 실행컨텍스트 | record | this | 콜백함수 | call, apply,bind

728x90
반응형

5. null과 undefined

- 값이 없는 겨우

- null : 개발자가 명시적으로 없다고 지정

- undefined : 변수에 값이 지정 안 됨 (메모리 주소 지정 x), 해당 데이터가 없을때, return문이 없는 함수

- ★(주의) typeof null = object  -> js 자체 버그임

 

6. 실행컨텍스트 및 콜 스택 소개

- 실행컨텍스트 (스코프, 변수, 객체, 호이스팅)

: 실행할 코드에 제공할 환경정보를 모아놓은 객체 (개발자가 작성한)

(1) 선언된 변수를 위로 끌어올림 = 호이스팅

(2) 외부 환경 정보 구성

(3) this 값 설정

 

- 스택 (stack) : 바스켓 같음 (LIFO : last in first out)

- 큐 (queue) : 원형 (FIFO : first in first out)

 

- 콜 스택 : 맨 위에 쌓이는 (노출되는) 순간 : 현재 코드에 관여하게 되는 시점이다.

 

7. record와 호이스팅1 (실행컨텍스트)

- 실행 컨텍스트 객체의 실체 (= 담기는 정보)

(1) variableEnvironment :  현재 컨텍스트 내의 식별자 정보(=record)  +  외부환경정보(=outer)

(2) LexcialEnvironment : variableEnvironment 동일 && 변경사항을 실시간으로 반영

(3) ThisBinding : this 식별자가 바라봐야할 객체

 

 

* variableEnvironment (VE) / LexcialEnvironment (LE)
- VE : 스냅샷 유지o (실시간 변동x) 

- LE : 스냅샷 유지 x (실시간 변동사항 반영) 

=> 실행 컨텍스트를 생성할때, VE에 정보 먼저 담고 -> 복사 -> LE를 이후에 활요함

 

** Record ( 현재 컨텍스트 내의 식별자 정보 ) + 호이스팅

- 식별자정보를 컨텍스트에 기록한다

- 수집 대상 정보 : 함수에 지정된 매개변수 식별자, 함수 자체, var로 선언된 변수 식별자 등

- 수집이 된다 = 호이스팅이 된다 (순서대로 수집 ! 실행 x)

 

 

** 호이스팅 (레코드와 관련됨: 식별자 개념을 수집할 때 호이스팅 발생)

- 가상개념임

- hoist : 끌어올리다 / 식별자 정보를 맨 위로 끌어올림 (레코드를 수집하는 과정임)

- 규칙 :  매개변수&변수는 선언부를 호이스팅함 / 함수는 위로 끌어올려졌다 (모든 함수x)

 

8. record와 호이스팅2 (함수의 호이스팅)

- 함수선언문 : 함수의 정의부만 존재 (할당 명령 x)

- 함수표현식 : 별도의 변수에 함수를 할당함 (익명함수 / 기명함수 : 함수의 이름을 적는 것: 활용성 낮음)

 

* LE = > 레코드의 수집과정= 호이스팅 

* 함수선언문 : 함수 전체가 위로 호이스팅

* 함수표현식 : 변수만 위로 호이스팅

 

** 주의할 점

( 함수선언문 ) 전체가 호이스팅 되서 전체가 영향을 줌

( 함수 표현식)은 변수만 위로 올려쓰니 이걸 습관화해서 사용해야함!!

 

9. outerEnvironmentReference (외부환경)

- 스코프 : 식별자에 대한 유효범위  

- 스코프 체인

: outer는 현재 호출된 선언당시(★) 

: LE를 참조하고 있음 (전 단계의 LE를 다음단계의 outer로 참조하고 있다)

 

* [정리]

각각의 실행 컨텍스트는 LE 안에 record와 outer를 가지고있고

그 실행 컨텍스트가 선언될 당시에 LE정보가 다 들어있으니

스코프 체인에 의해 상위 컨텍스트의 레코드를 읽기 가능

 

10. this (전역공간 this / 함수this / 메서드 this)

- 객체 지향 언어 (클래스로 생성한 인스턴스) / JS는 어디에서나 다양하게 사용가능

- 실행 컨텍스트 ( 실행할 코드에 제공할 환경정보를 모아놓은 객체)의 3가지 중 1개

- 실행 컨텍스트가 생성될 때 결정됨, 

 

- 전역공간 : this = 전역공간

: 런타임(코드가 돌아가는 환경) : 브라우저 : window 객체 / node : global 객체

 

* 비교

메서드 (종속되어 호출되어 사용 ) : 객체.메서드명();--객체에 대한 동작 수행 / 호출의 주체 = this = 객체

함수 ( 독립적으로 사용 가능) : 함수명();  / 호출의 주체 없음 (this= 전역객체) 

// this

let obj={
	methodA : function() {console.log(this)},
	inner : {
    		 methodB : function() {console.log(this)},
    		}
};

obj.methodA() ; //this === obj
obj['methodA']; //this === obj

obj.inner.methodB();         // this === obj.inner
obj.inner['methodB']();      // this === obj.inner
obj.['inner'].methodB();     // this === obj.inner
obj.['inner'].['methodB'](); // this === obj.inner

*  함수로서 호출할때 : 호출 주체 x --> 전역객체 의미함

 

11. this 우회방법 ( 콜백함수 this / 생성자 함수 this)

- this를 변수에 저장하고 콘솔을 변수를 찍어서 확인

- 화살표 함수 (= this를 바인딩하지 않은 함수) 

: 함수내부에서 this가 전역객체를 바라보는 문제(this유실) 때문에 도입됨

★ 화살표함수 & 일반함수의 큰 차이점은 : this binding 여부

 

* 콜백함수 호출시 그 함수 내부에서의 this 

--> 무조건 전역객체를 바라보게 되어있음 (윈도우 객체 / 글로벌 객체)

--> (예외: 콜백함수에 this를 지정한 경우 )

: 콜백함수도 함수임 (매개변수로 들어가는 함수)

(1) 별도지정없음 : 전역객체 

- setTimeout (function() {~~};

- function(x){~~};

(2) addListener 안에서의 this : 항상 호출한 주체의 element를 return

- function(e) {~~};

 

* 생성자 함수 내부에서의 this

- 생성자 : 구체적인 인스턴스(지금은 객체로 이해)를 만들기 위한 틀

- 새로운 인스턴스를 만들때마다 this가 달라짐

 

12. 명시적 this 바인딩 및 유사배열객체

- call, apply, bind 메서드 

(1) call

- this를 잃어버려 전역객체를 바라보는 상황

let func = function(a,b,c) {
	console.log(this,a,b,c); 
}

//no binding
func(1,2,3);      //global(~~) , a,b,c

//명시적 바인딩
//func.call({})
func({x:1},1,2,3); // {x:1} 4 5 6


//객체도 명시적바인딩 가능

let obj = {
	a:1 ,
    method: function(x,y){
    	console.log(this.a, x,y);
    }
}

//method 함수 안의 this는 항상 obj
obj.method(2,3); //1,2,3

//명시적바인딩
obj.method({a:4},5,6); //4,5,6

 

(2) apply

- call과 유사기능 

- 뒤에 있는 매개변수를 대괄호로 묶어줘야함

let func = function(a,b,c) {
	console.log(this,a,b,c); 
}

//명시적 바인딩-- apply
//func.call({})
func.apply({x:1},1,2,3); // {x:1} 4 5 6


//객체도 명시적바인딩 가능

let obj = {
	a:1 ,
    method: function(x,y){
    	console.log(this.a, x,y);
    }
}

//method 함수 안의 this는 항상 obj
obj.method(2,3); //1,2,3

//명시적바인딩
obj.method({a:4},[5,6]); //4,5,6

(3) 유사배열객체 

- 배열 (index, length)처럼 length가 필수 + index의 번호가 0부터 증가해야함

- ES6 ( Array,from)으로 쉽게 객체-> 배열 변환 가능

//유사배열객체 
//인덱스 0부터, length까지 가지고 있는 배열
//배열처럼 배열의 메서드는 못씀 (obj.push이런거 사용 불가능-> 유사하게 사용)
let obj ={
	
    0: 'a'
    1: 'b'
    2: 'c'
    length: 3
};

Array.prototype.push.call(obj,'d'); 
console.log(obj); // {0:'a',1:'b',2:'c',3:'d', length:4}

//ES6 (Array.from 메서드 등장)
//객체->배열 변환
let arrr = Array.from(obj);

 

13. Call | Apply | Bind 응용

(1) call
-중복되는 구간을 새로 만들어서 call사용하는 시점에 this 바인딩하

function Person(name,gender){
 this.name = name;
 this.gender = gender;
}

function Student(name,gender,school) {
    Person.call(this, name, gender);
    //this.name   = name;
    //this.gender = gender;
    this.school = school;
}

function Employee(name,gender,school) {
    Employee.call(this, name, gender);
    //this.name    = name;
    //this.gender  = gender;
    this.company = company;
}


var kd = new Student('길동','male','서울대');
var kd = new Student('길순','female','삼성');

(2) Apply

- Math.max.apply(null, 배열);

- spread operator

//1.
//비효율적인 최댓값,최솟값 찾기
let number = [10,20,3,16,45];
let max = (min =number[0]); //10
number.forEach(function (number){

//현재 돌아가는 숫자가 max보다 큰 경우
if(number > max) { max = number;}
if(number < min ) { min = number;}
}
console.log( max, min); 


//2.
//apply-> (this로 엮을 객체, 배열)
//apply-> ({},[]);

var numbers = [10,20,3,16,45];

//Math.max(1,2,3) -> apply를 사용하고 this는 null넣어줌, 그리고 배열 가져오기
let max = Math.max.apply(null, numbers); 
let min = Math.min.apply(null, numbers);



//3.
//스프레드 오퍼레이터
let max = Math.max(...numbers);
let min = Math.min(...numbers);

(3) Bind

//bind 메서드
// ->this를 바인딩하는 메서드
//call, apply랑 좀 다름 -> 즉시 호출하는 call,apply와 다름
//bind는 해당하는 함수를 새로운 함수를 return해서 저장 후 사용

//목적
//1. 함수에 this를 '미리' 적용
//2. 부분 적용 함수! 

let func = function(a,b,c,d){
	console.log(this, a,b,c,d);
}
func(1,2,3,4); // global 객체, 1,2,3,4

//목적1
//함수에 this를 미리 적용!
//새로운 함수의 return값을 받아야해서 변수에 넣기
let bindFunc1 = func.bind({x:1});  //새로운 함수 + this값은 1로 고정
bindFunc1(5,6,7,8); // {x:1} 5 6 7 8

//목적2
//부분 적용 함수!
let bindFunc1 = func.bind({x:1}, 4,5); //뒤에4,5를 미리 선점하기
bindFunc2(6,7); // 원래 4개 인자 필요한데, 2개 인자만 넣으면 됨 //{x:1} 4 5 6 7 


// name 프로퍼티!
// 'bound'라는 접두어 - bind의 수동태(바인드가 되었다)
// 추적하기 쉬움

console.log(func.name); // func
console.log(bindFunc1.name); // bound func
console.log(bindFunc2.name); // bound func

 

** 화살표함수는 this를 바인딩하는 과정이 없음

 

 

 

 

끝.

 

[출처]

1. 스파르타 코딩, JavaScript 문법 종합반 3주차 (5강-13강)

반응형