[POB#23] Core Javascript2(2) closure, this

dongwon·2021년 8월 19일
2

원티드-프리온보딩

목록 보기
17/25
post-thumbnail

8월 16일 강의 노트 정리(2)입니다.

closure

closure 정의

closure : 일급 객체 함수의 개념을 이용하여 스코프에 묶인 변수를 바인딩 하기 위한 일종의 기술

쉽게 말하면 함수를 선언할 때 만들어진 변수scope가 사라진 후에도 호출할 수 있는 함수를 의미합니다.

scope가 끝난 외부 함수의 변수를 참조할 수 있다.

closure 활용

var A = function () {
  var a = 1;

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

  return B;
};

var outer = A();
console.log(outer()); // 2
console.log(outer()); // 3
  1. var outerreturn B, 즉 B 함수를 의미합니다.
  2. A가 실행되면 실행 컨텍스트가 끝나고 scope가 종료됐지만, outer 함수는 B 함수를 바라보고 있습니다.
  3. 이 과정에서 변수 a는 사라졌지만, B 함수는 사라진 a를 바라보고 있습니다.
  4. 그 결과 outer 함수를 실행하고 console.log()로 확인해보면 변수 a의 값이 조작됐음을 알 수 있습니다.

closure 사용 시 주의사항

자바스크립트에는 기본적으로 사용하지 않는 변수들을 GC(Garvage Collector)가 수집합니다.
하지만 closure을 사용하게 된다면, 끝나버린 변수들을 GC에 수집되지 않고 메모리에 계속 남아있게 됩니다. (심하면 메모리 누수가 일어날 수 있음.)
이 문제를 해결하기 위해 위의 a 변수에 null이나, undefined를 넣어두면 해결할 수 있습니다.

this

this바라보는 객체를 의미합니다. 다른 언어들의 this와는 다르게 상황에 따라 바라보는 객체의 대상이 달라집니다.
this는 실행 컨텍스트가 실행될 때 결정됩니다. 실행 컨텍스트는 함수가 실행될 때 생성되므로 this함수가 호출될 때 가리킬 객체를 결정합니다.

다른 언어들의 this는 scope 안의 객체를 가리킵니다.

this의 동작 방식

1. 전역 공간에서의 this

전역 공간에서의 this는 당연하게도 window, node에서는 global 객체를 가리킵니다.

var a = "dongwon";
console.log(this.a); // dongwon

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

메서드로 호출될 땐 호출한 객체를 가리킵니다.

var name = "lee";

var user = {
  name: "kim",
  age: 27,
  getAge: function () {
    console.log(this.age);
  },
  friend: {
    name: "park"
    age: 29,
    getName: function () {
      console.log(this.name);
    },
  },/
// user.getName = user.child.getName의 의미
//   getName: function () {
//     console.log(this.name);
//   },
};

user.getAge();
user.friend.getName();

user.getName = user.child.getName;
user.getName();
  1. user.getAge(): 함수가 호출될 때의 this, 27을 가리킵니다.
  2. user.friend.getName() : 마찬가지로 user.friend 객체의 this, park을 의미합니다.
  3. userpropertygetName을 만들었다고 가정하면, 이때의 this는 user 객체를 가리킵니다. 따라서 kim을 의미합니다.

3. 메서드가 아닌 함수를 호출한 경우

함수로 호출한 경우 앞에 누가 호출했냐가 없을 땐 전역 객체를 가리킵니다.

var name = "global";

var user = {
  name: "method",
  getName: function () {
    console.log(this.name);

    var inner = function () {
      console.log(this.name);
    };

    inner();
  },
};

user.getName();
  1. getName thisuser가 호출했기 때문에 method를 의미합니다.
  2. inner 안의 this는 앞에 누가 호출했느냐가 없습니다. 즉 window, global을 의미합니다.

함수와 메서드의 차이

함수와 메서드 모두 function 키워드로 함수를 정의한 것을 말합니다.
둘의 차이점은 메서드는 객체의 property로 정의된 것을 의미합니다. 즉, 객체가 함수를 호출한 것, 객체.(함수)의 형태로 호출해야 메서드입니다.

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

호출됐을 때를 기준으로 하지 않고 직접 this가 가리킬 객체를 명시합니다.

call

함수를 호출할 때 객체 대상을 인자로 넘겨줍니다.

var user = {
  name: "kim",
  getName: function () {
    console.log(this.name);
  },
  friend: {
    name: "park",
    getName: function () {
      console.log(this.name);
    },
  },
};

user.friend.getName.call(user);
  1. friend를 바라보고 있지만, user를 인자로 넘기면서 this가 user을 가리키게 됩니다. 즉 kim을 의미합니다.

apply

call 메서드와 동일한 기능입니다. 인자를 배열로 넘길 때 사용합니다.

bind

call과 비슷하지만 호출하지 않고 묶어놓기만 합니다. 즉 this를 명시만 할 뿐 호출하지 않습니다.
클래스형 컴포넌트의 경우 아래와 같이 이벤트 핸들러를 bind 하지 않으면 this가 이벤트가 발생할 element를 가리키게 돼 의도치 않은 이벤트가 발생할 수 있습니다.
따라서 아래와 같이 명시적으로 호출하지 않고 가리킬 객체를 묶어놓기만 할 수 있습니다.

constructor(props){
    this.handleClick = this.handleClick.bind(this)
}

handleClick () { ... }

arrow function의 this

화살표 함수에서의 this는 어떤 객체를 호출했냐로 결정되는 것이 아닌, scope chain의 가장 가까운 객체가 this로 결정됩니다.
따라서 화살표 함수를 사용한다면 bind할 필요가 없습니다.

constructor(props){
    ...
}

handleClick = () =>{ ... }
profile
데이원컴퍼니 프론트엔드 개발자입니다.

0개의 댓글