[ydkjsy]Scope & Closures-8-The Module Pattern

Encapsulation and Least Exposure (POLE)

캡슐화(관련 정보와 동작 모음)와 가시성 통제가 모듈의 특징.

What Is a Module?

모듈은 관련 데이터, 함수(메소드) 모음집인데, public accessible details(public API)과 숨겨진 private details를 구분하는 특징이 있다.
그리고 다른 특징은 stateful. 시간이 지나면서 해당 정보에 접근, 업데이트하는 기능으로 정보들을 유지한다.

Namespaces (Stateless Grouping)

데이터 없이 관련 함수들만 묶은 경우.

// Util이라는 namespace 안에 함수들 형성, not module
var Utils = {
    cancelEvt(evt) {
        evt.preventDefault();
        evt.stopPropagation();
        evt.stopImmediatePropagation();
    },
    wait(ms) {
        return new Promise(function c(res){
            setTimeout(res,ms);
        });
    },
    isValidEmail(email) {
        return /[^@]+@[^@.]+\.[^@.]+/.test(email);
    }
};

Data Structures (Stateful Grouping)

data, stateful function but(캡슐화 충족),but not limiting 가시성.(POLE 면에서 부족)

// data structure의 인스턴스, not module
var Student = {
    records: [//접근 가능
        { id: 14, name: "Kyle", grade: 86 },
        { id: 73, name: "Suzy", grade: 87 },
        { id: 112, name: "Frank", grade: 75 },
        { id: 6, name: "Sarah", grade: 91 }
    ],
    getName(studentID) {
        var student = this.records.find(
            student => student.id == studentID
        );
        return student.name;
    }
};

Student.getName(73);
// Suzy

Modules (Stateful Access Control)

클래식 모듈

var Student = (function defineStudent(){
    var records = [
        { id: 14, name: "Kyle", grade: 86 },
        { id: 73, name: "Suzy", grade: 87 },
        { id: 112, name: "Frank", grade: 75 },
        { id: 6, name: "Sarah", grade: 91 }
    ];

    var publicAPI = {
        getName
    };

    return publicAPI;//함수로 바로 return 가능.

    // ************************

    function getName(studentID) {
        var student = records.find(
            student => student.id == studentID
        );
        return student.name;
    }
})();//IIFE, singleton. only need just one.

Student.getName(73);   // Suzy

Student는 모듈 인스턴스로 단일 method(getName)가 있는 public API를 제공하여 메소드를 통해 숨겨진 정보에 접근가능.
변수와 함수는 기본적으로 비공개 상태고, publicAPI에 저장된 것들만 외부에서 사용가능하게끔 한다.

Module Factory (Multiple Instances)

// module factory function, not singleton IIFE
function defineStudent() {//함수
    var records = [
        { id: 14, name: "Kyle", grade: 86 },
        { id: 73, name: "Suzy", grade: 87 },
        { id: 112, name: "Frank", grade: 75 },
        { id: 6, name: "Sarah", grade: 91 }
    ];

    var publicAPI = {
        getName
    };

    return publicAPI;

    // ************************

    function getName(studentID) {
        var student = records.find(
            student => student.id == studentID
        );
        return student.name;
    }
}

var fullTime = defineStudent();
fullTime.getName(73);            // Suzy

Classic Module Definition

  • 한번 이상 실행되는 모듈 팩토리 기능의 외부 범위가 있어야 함.
  • 모듈의 내부 범위에 적어도 하나의 숨겨진 상태(모듈)를 나타내는 정보가 있어야 함.
  • 숨겨진 module state에 대한 클로저를 갖고 있는 적어도 하나의 함수가 public API로 반환되어야 한다.

Node CommonJS Modules

클래식 모듈과 다르게, CommonJS 모듈은 파일마다 한 개.

module.exports.getName = getName;
//공용 API 무언가를 노출하기 위해
// module.exports 객체에 속성 추가

// ************************
//전역범위가 아닌 top-level scope.
var records = [
    { id: 14, name: "Kyle", grade: 86 },
    { id: 73, name: "Suzy", grade: 87 },
    { id: 112, name: "Frank", grade: 75 },
    { id: 6, name: "Sarah", grade: 91 }
];

function getName(studentID) {
    var student = records.find(
        student => student.id == studentID
    );
    return student.name;
}
//다중 모듈을 넣고 싶다면
Object.assign(module.exports,{
   // .. exports ..
});
// defining a new object for the API 위와같이 하자.
//module.exports = {
    // ..exports..
//};

가져올 때,

//singleton 인스턴스로 작동하여 동일 모듈을 여러번 가져와도 공유된 모듈 인스턴스의 참조를 얻음
var Student = require("/path/to/student.js");//해당 모듈의 전 publicAPI에 대한 참조

Student.getName(73);
// Suzy
//일부 참조
var getName = require("/path/to/student.js").getName;

// or alternately:

var { getName } = require("/path/to/student.js");

Modern ES Modules (ESM)

CommonJS와 비슷(파일 기준, 모듈 인스턴스 singleton). 그러나 ESM은 기본적으로 엄격모드.
export, import 키 사용.

//export
//다른 블록 내부는 안됨.
export { getName };
// 
export function getName(studentID) {
    // ..
}
//defulat export 
export default function getName(studentID) {
    // ..
}//non-default is named exports
//import
//named import
import { getName } from "/path/to/students.js";
//as
import { getName as getStudentName } from "/path/to/students.js";
getStudentName(73);
//default export => import 
import getName from "/path/to/students.js";
//named defualt mix!
import { default as getName, /* .. others .. */ } from "/path/to/students.js";
//namespace import, *는 export된 모든 것을 가져와 namespace아래에 저장. 
import * as Student from "/path/to/students.js";

좋은 웹페이지 즐겨찾기