336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

자바스크립트 THIS와 실행컨텍스트


자바스크립트에서 프로그램이 실행이 될때 자바스크립트는 실행컨텍스트를 생성한다. 실행컨텍스트는 전역컨텍스트와 함수컨텍스트가 있는데 초기 프로그램 실행시 전역컨텍스트가 생기고 함수컨텍스트는 함수 호출시 스택 자료구조 형태로 함수스택에 쌓인 후 가장 마지막에 있는 함수가 실행이 된다.

// 예제 1)

// 자바스크립트 실행 시 전역 컨텍스트가 생기고 다음 변수들과 선언된 함수들을 변수 객체에 저장한다.
var globalVariable = 'global';

// 이 함수가 호출 될 시 첫번쨰 함수 컨텍스트가 생기고 내부에 선언된 innerTest와 laterTest를 변수 객체에 저장한다.
function outerTest() {
  innerTest(); // 함수 선언전에 실행되어도 function 키워드로 선언시에는 컨텍스트 생성시 선언된 함수는 해당 컨텍스트의 변수객체에 저장이 된다.

  console.log('outer');  

  // 다음으로 이 함수 호출 시 두번째 함수 컨텍스트가 생기고 선언부 내 작업이 끝나면 해당 함수 컨텍스트는 함수스택에서 제거된다.
  function innerTest() {
    console.log('inner');
    console.log(globalVariable); // 스코프 체인을 통해 innerTest 컨텍스트에 해당 변수가 없으면 outerTest에서 해당 변수를 찾고 다시 찾지 못하면 최상위 global 컨텍스트에 저장된 변수를 찾는다. 전역컨텍스트 변수 객체에 globalVariable 이라는 변수가 저장이 되어있기 때문에 참조 가능.
}

}

outerTest(); // 첫번째 컨텍스트 생성

innerTest(); // undefined -> innerTest는 전역 스코프가 참조할수 없는 위치에 있기 때문에 실행되지 않는다.

//Result
'inner'
'global'
'outer'
// error => 'innerTest is not defined'

실행 컨텍스트 생성시 변수들과 함수 선언식으로 된 함수들을 먼저 변수객체에 저장 후 함수를 실행하기 때문에 다음과 같이 대입식으로 함수를 선언한 경우에 함수 호이스팅이 불가능하다.

예제 2)

// 함수 호이스팅

firstTest(); // 함수가 나중에 선언되어도 함수 선언식으로 선언된 함수는 호이스팅이 가능하다.

function firstTest() {
  console.log('first');
}

laterTest(); // 실행컨텍스트에서는 laterTest가 함수가 아닌 변수로 저장이 되어있고 값을 넣기전에 호출하려고 하면 자바스크립트는 해당 변수에 함수 대입을 하기 전에 실행하려고 하기떄문에 위에서는 laterTest is not a function 이라는 에러메시지를 받게 된다.

var laterTest = function() { // 함수 표현식으로 laterTest에 함수 대입 할 경우 호이스팅이 불가능하다. 
  console.log('later');
}

// result
'first'
// error => 'laterTest is not defined'

컨텍스트는 스코프 체인, 변수객체, this 로 구성되어 있는데 인자와 변수는 변수객체에 저장이되고, 스코프체인은 함수 선언시의 상위 스코프를 저장한다. 그리고 this 는 new 연산자로 생성한 인스턴스가 아니라면 실행컨텍스트 안에서의 내부적으로 정해진 this이다. 보통 브라우저에서는 이 this 가 window로 node 에서는 global 객체로 지정되어 있다.

this는 인자로 받는 변수 명과 내부에서 선언된 변수 명이 같을 경우 이를 구분하기 위해 주로 사용된다.

여기서 this를 변경하려면 apply, bind, call 등의 임의로 변경하게 할 수 있는 api를 사용하거나 객체 내부에서 선언된 메서드를 호출 할 경우 자바스크립트는 내부적으로 this를 해당 객체로 지정 할 수 있다.

예시 3) new 연산자로 this를 지정할 경우

function Person(name, age) {
  this.name = name;
  this.age = age;
  this.gender = 'M'

  console.log(this.name); // '정슬기'
  console.log(this.age);  // 31
  console.log(this.gender) // 'M'
}

var user = new Person('정슬기', 31);

// Result
'정슬기'
31
'M'

예시 5) 객체 내부에서 선언된 메서드를 호출 할 경우

var Person = {
   name : '정슬기',
   age : 31,
  gender : 'M',

   consoleLog : function() {
      console.log(this.name); // '정슬기'
      console.log(this.age);  // 31
      console.log(this.gender) // 'M'      
    },

   // 주의 ! arrow function의 경우 this 는 윈도우 객체임
   consoleLogArrow : () => {
      console.log(this.name); // "" 상위 오브젝트(window)에 name 프로퍼티 존재
      console.log(this.age);  // undefined
      console.log(this.gender) // undefined
    }
}

Person.consoleLog();
Person.consoleLogArrow();


// consoleLog() Result
'정슬기'
31
'M'
// consoleLogArrow() Result
""
undefined
undefined

예시 6) bind, call, apply 를 사용할 경우

function Person() {
    console.log(this.name); // '정슬기'
    console.log(this.age);  // 31
    console.log(this.gender) // 'M'
}

var user = {
name : '정슬기',
  age : 31,
  gender : 'M'
}

// call을 이용
Person.call(user);

// bind를 이용
var bindTest = Person.bind(user);
bindTest();

// apply를 이용
Person.apply(user);

// Result
'정슬기'
31
'M'

'웹프로그래밍 > Javascript' 카테고리의 다른 글

이벤트 루프 Job Queue , Event Queue 차이?  (1) 2019.12.15
비동기  (0) 2019.12.15
자바스크립트 - 타입체크  (0) 2019.12.02
자바스크립트 - 스코프  (0) 2019.12.02
자바스크립트 - 프로토타입  (0) 2019.12.02

+ Recent posts