/* user2.js 파일에서 exports 객체를 할당하였으므로, require()를 호출할 때 자바스크립트에서 새로운 변수로 처리한다. 결국 아무 속성도 없는 {}가 반환된다. */var user =require('./user2');console.dir(user);functionshowUser(){returnuser.getUser().name +','+user.group.name;}console.log(showUser);
노드는 모듈을 처리할 때 exports를 속성으로 인식한다. 이 속성에 함수나 객체를 속성으로 추가하면 모듈을 불러들인 쪽에서 exports에 추가된 속성들을 참조할 수 있다. 그러나 exports에 객체를 할당하면 모듈 파일 안에서 선언한 exports는 모듈 시스템에서 처리할 수 있ㄴ는 전역변수가 아닌 단순 변수로 인식된다. 이때문에 참조할 수 없게된다.
module.exports를 사용해 객체를 그대로 할당하기
//module.exports에는 객체를 그대로 할당할 수 있다.var user = {getUser:function(){return {id:'test01',name:'박우진'}; }, group : {id:'group1',name:'친구'}}module.exports= user;
// require()메소드는 객체를 반환var user =require('./user3');functionshowUser(){returnuser.getUser().name +','+user.group.name;}console.log(showUser());
module.exports에 객체를 그대로 할당하면 모둘파일 안에서 할당한 객체를 참조할 수 있다.
module.exports에 함수만 할당하기
//인터페이스(함수 객체)를 그대로 할당할 수 있다.module.exports=function(){return {id:'test01',name:'박우진'}};
//require()메소드는 함수를 반환var user =require('./user4');functionshowUser(){returnuser().name+','+'No group';}console.log(showUser());
반환된 함수에 소괄호만 붙여주면 함수를 그대로 실행할 수 있다.
exports와 module.exports 함께 사용하기
module.exports가 우섡으로 적용된다. 즉, 모듈을 불러오는 쪽에서는 module.exports에 할당된 객체나 속성을 참조할 수 있으며 exports 전역 변수는 무시된다.
//require()메소드는 exports가 아닌 module.exports로 설정된 속성 반환var user =require('./user5');functionshowUser(){returnuser.getUser().name +user.group.name;}console.log(showUser());
require() 메소드의 동작 방식 이해하기
//가상으로 require()함수를 정의해 보면 require()함수가 내부적으로 처리되는 방식을 이해할 수 있따.varrequire=function(path){var exports = {getUser:function(){return {id:'test01',name:'박우진'}; }, group: {id:'group01',name:'친구'} }returnexports;}var user =require('...');functionshowUser(){returnuser.getUser().name +user.group.name;}console.log(showUser());
모듈을 분리할 때 사용하는 전형적인 코드 패턴
코드패턴
설명
함수를 할당하는 경우
모듈 안에서 함수를 만들어 할당한다.
모듈을 불러온 후 소괄호를 붙여 모듈을 실행한다.
인스턴스 객체를 할당하는 경우
모듈 안에서 인스턴스 객체를 만들어 할당한다.
모듈을 불러온 후 해당 객체의 메소드를 호출하거나 속성을 사용할 수 있다.
프로토타입 객체를 할당하는 경우
모듈 안에서 프로토타입 객체를 만들어 할당한다.
모듈을 불러온 후 new연산자로 인스턴스 객체를 만들어 사용할 수 있다.
1. 함수를 할당하는 코드 패턴
//사용패턴 : exports에 속성으로 추가된 함수 객체를 그대로 참조한 후 호출exports.printUser=function(){console.log('user이름은 박우진');};
//exports에 속성으로 추가된 함수 객체를 그대로 참조한 후 호출var printUser =require('./user7').printUser;printUser();
// new연산자로 만든 인스턴스 객체를 할당한 후 인스턴스 객체 호출var user =require('./user8');user.printUser();
// exports에 인스턴스 객체를 할당할 경우exports.user =newUser('test01','박우진');// new연산자로 만든 인스턴스 객체를 할당한 후 인스턴스 객체 호출var user =require('./user9').user;user.printUser();
3.프로토타입 객체를 할당하는 코드 패턴
//user.js...exports.user = User;//module_test.jsvar User =require('./user10');var user =newUser('test01','박우진');user.printUser();
07-2 사용자 정보 관련 기능을 모듈화하기
스키마 파일을 별도의 모듈 파일로 분리하기
스키마는 컬렉션의 구조를 결정하는 것으로 데이터베이스와 분리해서 독립적으로 정의할 수 있다.
var crypto =require('crypto');var Schema={ };Schema.createSchema=function(mongoose){// 스키마 정의// password를 hashed_password로 변경, 각 칼럼에 default 속성 모두 추가, salt 속성 추가 UserSchema =mongoose.Schema({ id: {type: String, required:true, unique:true,'default':''}, hashed_password: {type: String, required:true,'default':''}, salt: {type:String, required:true}, name: {type: String, index:'hashed','default':''}, age: {type: Number,'default':-1}, created_at: {type: Date, index: {unique:false},'default':Date.now}, updated_at: {type: Date, index: {unique:false},'default':Date.now} });// password를 virtual 메소드로 정의 : MongoDB에 저장되지 않는 가상 속성임. // 특정 속성을 지정하고 set, get 메소드를 정의함 UserSchema.virtual('password').set(function(password) {this._password = password;this.salt =this.makeSalt();this.hashed_password =this.encryptPassword(password);console.log('virtual password의 set 호출됨 : '+this.hashed_password); }).get(function() {console.log('virtual password의 get 호출됨.');returnthis._password; });// 스키마에 모델 인스턴스에서 사용할 수 있는 메소드 추가// 비밀번호 암호화 메소드UserSchema.method('encryptPassword',function(plainText, inSalt) {if (inSalt) {returncrypto.createHmac('sha1', inSalt).update(plainText).digest('hex'); } else {returncrypto.createHmac('sha1',this.salt).update(plainText).digest('hex'); } });// salt 값 만들기 메소드UserSchema.method('makeSalt',function() {returnMath.round((newDate().valueOf() *Math.random())) +''; });// 인증 메소드 - 입력된 비밀번호와 비교 (true/false 리턴)UserSchema.method('authenticate',function(plainText, inSalt, hashed_password) {if (inSalt) {console.log('authenticate 호출됨 : %s -> %s : %s', plainText,this.encryptPassword(plainText, inSalt), hashed_password);returnthis.encryptPassword(plainText, inSalt) === hashed_password; } else {console.log('authenticate 호출됨 : %s -> %s : %s', plainText,this.encryptPassword(plainText),this.hashed_password);returnthis.encryptPassword(plainText) ===this.hashed_password; } });// 값이 유효한지 확인하는 함수 정의varvalidatePresenceOf=function(value) {return value &&value.length; };// 저장 시의 트리거 함수 정의 (password 필드가 유효하지 않으면 에러 발생)UserSchema.pre('save',function(next) {if (!this.isNew) returnnext();if (!validatePresenceOf(this.password)) {next(newError('유효하지 않은 password 필드입니다.')); } else {next(); } })// 필수 속성에 대한 유효성 확인 (길이값 체크)UserSchema.path('id').validate(function (id) {returnid.length; },'id 칼럼의 값이 없습니다.');UserSchema.path('name').validate(function (name) {returnname.length; },'name 칼럼의 값이 없습니다.');UserSchema.path('hashed_password').validate(function (hashed_password) {returnhashed_password.length; },'hashed_password 칼럼의 값이 없습니다.');// 스키마에 static으로 findById 메소드 추가UserSchema.static('findById',function(id, callback) {returnthis.find({id:id}, callback); });// 스키마에 static으로 findAll 메소드 추가UserSchema.static('findAll',function(callback) {returnthis.find({}, callback); });console.log('UserSchema 정의함.');return UserSchema;}//module.exports에 UserSchema 객체 직접할당module.exports= Schema;
//app.js// user 스키마 및 모델 객체 생성functioncreateUserSchema() {//user_schema.js 모듈 불러오기 UserSchema =require('./database/user_schema').createSchema(mongoose);// User 모델 정의 UserModel =mongoose.model("users3", UserSchema);console.log('users3 정의함.');}