> For the complete documentation index, see [llms.txt](https://simplejs.gitbook.io/olaf/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://simplejs.gitbook.io/olaf/12.-module-pattern.md).

# 14. 모듈 패턴 (Module pattern)

## 모듈 패턴

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

```javascript
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)

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

```javascript
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` 이런 식으로 접근하여 값을 바꿀 수 있습니다.

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

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

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

### 캡슐화

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

```javascript
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 의 값을 확인할 수 있습니다.<br>

### 팁

#### 즉시 실행 함수

```javascript
var iphone = phone() 
```

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

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

```javascript
(function(){
	// 실행구문 
})(); // 선언과 동시에 실행이됩니다.
var pF = (function(){ 
	return 5
})();
console.log(pF) // 5
```

```javascript
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()` 이런식으로 한번 더 함수를 실행시켜서 담아야되는 부분을 줄일 수 있습니다.

#### 생성자함수&#x20;

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

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

#### 라이브러리 스코프

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

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