[마스터 개념] 9 | 클로져, this

728x90

[마스터 개념] 9 | 클로져, this

1 variable 변수

2 operator 연산자

3 function 함수

4 object 객체

5 class 클래스

7 built-in 빌트인 객체

8 array 배열

9 iterator 이터러블

10 map

11 more-operators 유용한 연산자들

12 module 모듈

13 promise 프로미스

14 scope 스코프

15 prototype 프로토타입

16> closure 클로져

17> this 

15 closure 클로져

클로져

 

내부 함수가 외부 함수의 변수를 기억하게 한다.

즉, 외부 함수가 호출되어 실행된 후에도 내부 함수는 외부 함수의 변수에 접근할 수 있다.

외부에서는 그 변수를 직접 접근할 수 없도록 만들어 준다.

> 변수를 보호, 상태의 캡슐화

 

function outer() {
  const x = 0;
  function inner() {
    console.log(`inside inner : ${x}`);
  }
  return inner;
}
const func1 = outer();
func1();		// inside inner : 0

 

 outer( ) 는 inner 의 참조값을 반환한다. 근데 func1 에 inner 의 참조값이 할당됐으므로 inner( ) 가 할당된다.

 

 이때, 클로져에 의해 함수뿐만(inner( )) 아니라 변수가 들어있는 렉시컬 환경도(x = 0) 함께 묶여서 반환되기 때문에 inner 의 x 값이 0으로 나타날 수 있다.

 

function makeCounter() {
  let count = 0;
  function increase() {
    count++;
    console.log(count);
  }
  return increase;
}

const increase = makeCounter();
increase();		// 1
increase();		// 2
increase();		// 3

// ----------------------------

class Counter {
  #count = 0;
  increase() {
    this.#count++;
    console.log(this.#count);
  }
}
const counter = new Counter();
counter.increase();	// 1

 

 이때, increase( ) 를 통해서만 count 를 조작할 수 있다.

 

 따라서 클로져는 내부 정보를 은닉하고, 공개 함수(public, 외부) 를 통한 데이터 조작을 위해 쓰인다. 클래스 private 필드나 메서드를 사용하는 효과와 동일하다.

 

// let과 var의 차이점!
function loop() {
  const array = [];
  for (let i = 0; i < 5; i++) {
    array.push(function () {
      console.log(i);
    });
  }
  return array;
}

const array = loop();
array.forEach((func) => func());
// 0 1 2 3 4

 

 loop( ) 함수는 array 에 i 를 출력하는 함수들이 들어있는 배열의 참조값을 반환한다. 이때, let 은 블록스코프 이기 때문에,  for 문의 let i = 0 의 값도 클로져에 의해 i 를 출력하는 함수와 묶여서 반환된다.

 

 따라서 각각의 함수들은 클로져에 의해 외부의 블록스코프에 함께 i 의 정보를 가진다.

 

// let과 var의 차이점!
function loop() {
  const array = [];
  for (var i = 0; i < 5; i++) {
    array.push(function () {
      console.log(i);
    });
  }
  return array;
}

const array = loop();
array.forEach((func) => func());
// 5 5 5 5 5

 

 var 는 함수스코프이기 때문에, 최종적으로 i = 5인 하나의 변수로만 남아있다.

 

this

 

 자바스크립트에서는 호출하는 사람에 의해 동적으로 결정된다.

 

function Cat(name) {
  this.name = name;
  this.printName = function () {
    console.log(`고양이 이름 : ${this.name}`);
  };
}

function Dog(name) {
  this.name = name;
  this.printName = function () {
    console.log(`강아지 이름 : ${this.name}`);
  };
}

const cat = new Cat("냐옹");
const dog = new Dog("멍멍");
cat.printName();		// 고양이 이름 : 냐옹
dog.printName();		// 강아지 이름 : 멍멍

dog.printName = cat.printName;

dog.printName();		// 고양이 이름 : 멍멍
cat.printName();		// 고양이 이름 : 냐옹

 

 Object.함수( ) 를 하면 해당 Object 가 this 로 바인딩된다.

 

 정적으로 this 를 바인딩하는 방법

 1. bind 함수를 이용하여 수동으로 바인딩 ( this.함수 = this.함수.bind(this) )

 2. arrow 함수를 이용 : arrow 함수는 렉시컬 환경에서의 this를 기억하고, arrow 함수 밖에서 제일 근접한 스코프의 this 를 가리킴 ( this.함수 = ( ) => { 함수내용 } )

 

arrow 함수

 

 화살표 함수
  1. 문법이 깔끔
  2. 생성자 함수로 사용이 불가능 (무거운 프로토타입 만들지 않음)
  3. 함수 안에 무거운 arguments 객체를 가지고 있지 않음

   - arguments 출력하면, arrow 함수 외부의 argumetns 를 참조만 함
  4. this에 대한 바인딩이 정적으로 결정
    - 함수에서 제일 근접한 상위 스코프의 this에 정적으로 바인딩 됨

 

 

 

 

 

 

 

 

 

 

728x90