ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [JavaScript] This, Closure
    JavaScript 2024. 1. 21. 08:00
    728x90
    반응형

    this, closure

    this

    this란?

    자바스크립트에서의 this는 함수 호출 방식에 따라서 결정됨

    함수의 호출방식

    • 메소드로서의 호출

    메소드로 호출 시(ex: obj1.addNums) 자신을 호출한 대상이 this

    • 함수로서의 호출

    함수를 독립적으로 호출 시 호출주체를 알 수 없으므로 this 지정 x -> 때문에 this는 전역 객체를 가리킴
    또한 메소드의 내부라고 해도 함수로서 호출하면 this는 전역객체를 의미함

    • 콜백함수로 호출될 때 그 함수 내부에서의 this

    콜백함수도 함수이기 때문에 this는 전역객체를 참조하지만, 콜백함수를 넘겨받은 함수에서 별도로 this를 지정한 경우 예외적으로 그 대상을 참조함

    • 생성자 함수 호출

    this는 인스턴스를 가리킴

    • apply, call, bind 호출

    apply, call, bind는 원하는 this를 바인딩할 수 있는 메소드임

    1. apply
    var func = function (a, b, c) {
    console.log(this, a, b, c);
    };
    
    func.apply({ x: 1 }, [4, 5, 6]); // { x: 1 } 4 5 6
    
    var obj = {
    a: 1,
    method: function (x, y) {
    console.log(this.a, x, y);
    }
    };
    
    obj.method.apply({ a: 4 }, [5, 6]); // 4 5 6
    
    1. call
    var func = function(a,b,c) {
       console.log(this, a,b,c,)
    }
    
    func(1,2,3) // window{…} 1 2 3
    
    func.call({x: 1}, 2,3,4) // {x:1} 2 3 4
    
    1. bind
      call이나 apply랑 비슷해보이지만 call과 다르게 즉시 호출하지 않고 넘겨받은 this 및 인수들을 바탕으로 새로운 함수를 리턴하는 메소드
    var func = function (a,b,c,d) {
      console.log(this, a,b,c,d)
    }
    func(1,2,3,4) // this는 window 객체 가리킴
    
    var bindFunc = func.bind({x:1})
    bindFunc(5,6,7,8) // {x:1}, 5, 6, 7, 8
    
    // 부분 적용함수 
    var bindFunc2 = func.bind({x:1, 4, 5}) 
    bindFunc2(6,7) // {x:1}, 4, 5, 6, 7
    

    Closure

    Closure란?

    외부함수의 생명주기가 이미 종료되었음에도 내부함수가 외부 함수의 컨텍스트에 접근할 수 있는 것을 말함 → 이미 종료된 외부함수의 변수 등을 여전의 참조(외부함수의 렉시컬 환경을 여전히 참조)할 수 있음

    어떻게 접근할 수 있냐면 가비지 컬렉터가 보고 외부함수의 렉시컬환경을 아직 참조하는 곳이 있어 냅두기 때문임

    예시
    const x = 1;
    
    function outer() {
      const x = 10;
      const inner = function () {
        console.log(x); // 10
      };
      return inner;
    }
    
    const innerFunc = outer();
    innerFunc();

    const innerFunc = outer() <- 이 부분에서 outer 함수를 호출하고 그 결과인 inner 함수를 innerFunc에 할당함
    outer 함수는 inner 함수를 반환한 후 콜스택에서 사라짐. 하지만 outer 함수의 렉시컬 환경은 inner 함수가 여전히 참조하고 있으므로 사라지지 않음
    innerFunc() <- inner 함수를 호출하면 이 함수는 자신이 선언됐던 렉시컬 환경인 outer 함수의 환경을 참조하여, outer 함수 내부에 선언된 x 변수를 사용할 수 있음. 이렇게 함수가 자신이 선언된 환경을 기억하는 특성이 바로 클로저임
    inner 함수는 console.log(x)를 실행한 후 콜스택에서 사라짐
    따라서 함수가 생성될 때 렉시컬 환경을 기억하고, 이후에도 그 환경에 접근할 수 있는 이런 특성이 클로저임. 이를 통해 함수 외부에서 접근할 수 없는 private한 변수를 만들 수 있음

     

    그러면 클로저는 왜 사용하는 걸까?

    1. 상태유지
      현재 상태를 기억하고 변경된 최신 상태를 유지하는 것
    예시
    function makeCounter() {
      let count = 0;
    
      return function() {
        return count++;
      }
    }
    
    let counter1 = makeCounter();
    
    console.log(counter1());  // 0
    console.log(counter1());  // 1
    
    1. 전역 변수 사용 억제
      자신이 생성되었을 때의 lexical 환경을 기억하기 때문
    예시
    let count = 0;
    
    function makeCounter() {
      return function () {
        return ++count;
      };
    }
    
    let counter1 = makeCounter();
    
    console.log(counter1(), "before"); // 0
    count = 1000;
    console.log(counter1(), "after"); // 1001
    1. 정보의 은닉
    예시
    // 생성자 함수
    function Person(name, age) {
      this.name = name; //public
      let _age = age; //private
    
      this.sayHi = function () {
        console.log(`Hi! My name is ${this.name}. I am ${_age}.`);
      };
    }
    
    const me = new Person("Choi", 33);
    me.sayHi(); // Hi!, My name is Choi. I am 33.
    console.log(me.name); // Choi
    console.log(me._age); // undefined
    
    const you = new Person("Lee", 30);
    you.sayHi(); // Hi! My name is Lee. I am 30.
    console.log(you.name); // Lee
    console.log(you.age); // undefined
    

    위 코드에서 me._age나 you.age에 접근하면 undefined가 나오는 이유
    _age는 Person 함수의 내부에서만 사용하는 변수라서 외부에서 접근할 수 없음
    변수 _age는 Person 함수 내부에서만 접근가능하고(은닉화), 함수가 종료되면 콜스택에서 사라지지만 클로저로 인해 메소드 SayHi 함수에서 계속 접근이 가능함

    me.name이 되는 이유는 Person 객체의 인스턴스의 name 속성을 나타내고, 이 속성은 어디서든 접근가능하고 변경할 수 있는 public 속성이기 때문임. 따라서 me.name이나 you.name이라고 하면 그 속성값이 나옴

    반응형
Designed by Tistory.