클로저

kler_HJ·2020년 7월 1일

INTERVIEW

목록 보기
4/5

클로저 (Closure)

MDN에서는 클로저를 아래와 같이 설명하고있다.

클로저는 함수와 함수가 선언된 어휘적 환경의 조합이다.

자바스크립트에서 함수 내에 선언된 변수는 함수 내에서만 접근이 가능한 지역 변수 속성을 갖는다.
하지만, 함수 내에서 함수 밖에 선언된 변수에 접근하는 것은 당연히 가능하다.

예시

function makeFunc() {
  var name = 'local';
  function displayName() {
    alert(name);
  }
  return displayName;
}

var myFunc = makeFunc();
//myFunc변수에 displayName을 리턴함

//유효범위의 어휘적 환경(실행 환경)을 유지
myFunc();
//리턴된 displayName 함수를 실행(name 변수에 접근)

var name = 'local' 은 makeFunc() 함수 내에서 선언된 지역 변수이지만 displayName() 함수 입장에서는 함수 밖에 선언된 변수이므로 name 변수에 접근이 가능하다.

따라서, var myFunc은 makeFunc()의 리턴 값으로 function displayName()을 받아 displayName()의 실행 환경, 즉 클로저도 함께 전달받는다.


조금 더 구체적인 사용 예시

function makeAdder(x) {
  var y = 1;
  return function(z) {
    y = 100;
    return x + y + z;
  };
}

var add5 = makeAdder(5);
var add10 = makeAdder(10);
//클로저에 x와 y의 환경이 저장됨

console.log(add5(2));  // 107 (x:5 + y:100 + z:2)
console.log(add10(2)); // 112 (x:10 + y:100 + z:2)
//함수 실행 시 클로저에 저장된 x, y값에 접근하여 값을 계산

makeAdder(x)를 이용해 서로 다른 클로저 (x=5, x=10)를 가진
변수 add5, add10를 사용하는 예시이다.


클로저로 객체의 private method처럼 사용하기

var counter = (function() {
  var privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment: function() {
      changeBy(1);
    },
    decrement: function() {
      changeBy(-1);
    },
    value: function() {
      return privateCounter;
    }
  };   
})();

console.log(counter.value()); // logs 0
counter.increment();
counter.increment();
console.log(counter.value()); // logs 2
counter.decrement();
console.log(counter.value()); // logs 1

counter는 클로저로 지역 변수 privateCounter의 값을 다루는
increment, decrement, value methods 를 갖는다.

(function())()은 즉시 실행 함수로,
function()의 선언과 동시에 return 값을 좌항의 counter에 전달한다.



클로저와 prototype

function MyObject(name, message) {
  this.name = name.toString();
  this.message = message.toString();
  this.getName = function() {
    return this.name;
  };

  this.getMessage = function() {
    return this.message;
  };
}

위의 MyObject는 this.getName과 this.getMessage가 클로저를 형성하여 this.name, this.message에 접근하고있다.

const object1 = new myObject("kler", "hi"); // object1에 name, message, getName, getMessage 전부 할당
const object2 = new myObject("hj", "hi"); // object1에 name, message, getName, getMessage 전부 할당

이는 myObject의 생성자가 호출될 때마다 동일한 getName, getMessage 메소드를 새로 할당하기 때문에 비효율적이다.



prototype

function MyObject(name, message) {
  this.name = name.toString();
  this.message = message.toString();
}

// prototype 이용
MyObject.prototype.getName = function() {
  return this.name;
};
MyObject.prototype.getMessage = function() {
  return this.message;
};

이처럼 함수의 prototype에 메소드를 정의하면 객체 생성시마다 메소드를 별도로 할당하지 않아 처리 속도메모리 소비량향상시킬 수 있다.




참고

profile
더 나은 제품과 디자인에 대해 고민하기를 즐기는 Front-end 개발자입니다.

0개의 댓글