14. 모듈 패턴 (Module pattern)

모듈 패턴

변수가 섞일 수 있기 때문에 JS 에서는 전역변수를 만드는 일은 지양 하라고 하고있습니다.

var a = 5;
function changeNum() {
  a = 8; // 전역의 a를 8로 바꿨어요
}
function changeNum2() {
  a = 3; // 전역의 a가 바뀐줄 모르고 전역의 a를 3으로 바꿨어요
}
changeNum();
changeNum2();
console.log(a); // 최종 a는 3

문제의 해결 방법은 전역 변수 대신 함수 안에 넣어 지역 변수로 만드는 겁니다. 아니면 객체 안의 속성으로 만드는 방법도 있습니다.

1. 네임 스페이스 (Name space)

이름을 가진 공간을 만들어서 모듈화를 합니다.

var x = 5; // 전역 변수

// obj 네임스페이스
var obj = {
  x: "local", // 네임스페이스 안의 x 값
  y: function() {
    alert(this.x); // 객체안에서의 this는 obj 자신을 의미합니다. this.x = local 입니다.
  }
};
console.log(x); // 5

전역변수와 네임스페이스 공간이 분리되었습니다. 하지만 한가지 문제가 있습니다. obj 는 public 하게 접근이 가능합니다. 즉 누구나 obj.x = global 이런 식으로 접근하여 값을 바꿀 수 있습니다.

var obj = {
  x: "local",
  y: function() {
    alert(this.x);
  }
};
obj.x = "global"; // 누군가 obj 안에있는 x를 장난으로 global로 바꿔버렸어요
obj.y();

전역 변수 사용을 피하기 위해 네임스페이스라는 공간을 만들어서 내부에 넣어놨지만 public 하기 때문에 누구든 건들 수 있다는 문제가 생겼습니다. 이 때 등장하는 개념이 캡슐화 (private) 라는 개념인데요 내부 값들을 비공개로 두는 것 입니다.

리모콘이 하나 있다고 할게요 리모콘 내부는 저도 어떻게 동작하는지 모르겠지만 .. 많은 부속품들이 있겠죠? 만약 부속품들이 다 밖으로 나와 있다면 애기들이 만져서 고장내기 쉬울겁니다. 위와 같은 일을 방지하기 위해 플라스틱으로 감싸고 동작할 수 있는 버튼들만 밖으로 내보내고, 부품은 감쌌습니다. 이게 캡슐화입니다. 내부 부속품(변수, 배열, 객체 등 ..)등은 감싸고 동작하는 버튼(함수)를 내보냄으로써 내보낸 함수들을 통해 부속품을 동작, 조작할 수 있게 해주는 방식을 말합니다.

캡슐화

어떻게 내부 변수들을 감쌀 수 있을까요? 스코프를 이용하는 것입니다. 이전 시간에 배운 클로저가 등장합니다.

function phone () {
	// power 변수를 phone 안으로 감춘다.
	var power = 'on' // 부품이라고 예를 들겠습니다.

    function checkPower () { // 전원 버튼
		console.log(power) // 눌렸을 때 전원 여부를 알려준다.
	}

	function playMusic () {
		console.log('노래를 실행합니다.')
	}
	// 밖에서 쓰게할 이름 : 함수
	return {
		checkPower: checkPower,
		playMusic: playMusic
	}
}

var iphone = phone() // return {}
iphone.playMusic() // '노래를 실행합니다.'
iphone.checkPower() // 'on' 

밖의 스코프에서는 안쪽 스코프의 접근이 불가능하다는 것을 이용하였습니다. power 라고 불리는 변수를 감추고 checkpower, playMusic 두 가지 기능을 정의하여 사용자에게 제공해주었습니다. 사용자는 power 라는 변수를 모르더라도 던져준 함수만으로 power 의 값을 확인할 수 있습니다.

즉시 실행 함수

var iphone = phone() 

phone 의 기능들을 사용하기 위해 위의 코드와 같이 한번 return 을 받을 후 에 사용하는 단계를 즉시 실행 함수를 이용하면 줄일 수 있습니다.

즉시 실행함수는 아래와 같이 생겼습니다.

(function(){
	// 실행구문 
})(); // 선언과 동시에 실행이됩니다.
var pF = (function(){ 
	return 5
})();
console.log(pF) // 5
var privateFunc = (function () { 
  var x = 'local'; 
  function getX() { // getX() 라는 함수는 내부변수 x = local을 알림창에 찍어주는 역할을 해요
    alert(x);
  }
  return { 
  	getX : getX // getX 라는 이름으로 getX()를 내보내는 겁니다.
  };
})(); // 이런식으로 감싸주시면 됩니다.
console.log(privateFunc);  // {getX: ƒ}

var pF = privateFunc() 이런식으로 한번 더 함수를 실행시켜서 담아야되는 부분을 줄일 수 있습니다.

생성자함수

이전에 배웠던 생성자 함수와 같이 이용하면 조금 더 이쁜 코드를 작성할 수 있습니다.

var Person = (function(){ // 리턴된 생성자함수를 Person 변수에 담고있습니다.
  function Person(name) { // 내부에 생성자 함수를 만들어줍니다.
    this.name = name;
  }
  Person.prototype.getName = function(){ // 생성자에 프로토타입 함수도 작성해주고요!
    console.log(this.name);
  };
  return Person; // 완성된 생성자함수를 밖으로 던져줍니다.
})(); // 즉시실행으로 감싸줍니다.
console.dir(Person);

라이브러리 스코프

즉시 실행을 사용하면 좋은점이 있는데요 JQuery에서는 $라는 표현을 사용하는거 알고계신가요? 그런데 다른 라이브러리에서도 $를 쓴다면 $가 겹치겠죠? 그때 즉시 실행 함수로 경계를 나눌 수 있습니다.

var Person = (function($){ // 여기서 $는 밖에서 넣어준 jQuery를 의미해요!
  // 내부의 $는 다 jQuery 입니다.
})(jQuery); // 실행부에 jQuery를 넣어줍니다.
var Toy = (function($){ // 여기서 $는 밖에서 넣어준 다른라이브러리 의미해요!
  // 내부의 $는 다른라이브러리 입니다.
})(다른라이브러리); // 실행부에 다른라이브러리 넣어줍니다.

Last updated