node.js의 express.js 한줄 한줄 분석하고 있습니다.
var EventEmitter = require('events').EventEmitter;
var mixin = require('merge-descriptors');
function createApplication() {
var app = function(req, res, next) {
app.handle(req, res, next);
};
/**
* merge-descriptors의 경우 두번째 인자의 프로퍼티를 첫번째 인자의 프로퍼티로 복사해줌
* 세번째 인자가 true인 경우 첫번째 인자에 이미 존재하는 프로퍼티를 두번째 인자의 프로퍼티로 덮어 씌움
*/
mixin(app, EventEmitter.prototype, false);
/**
* EventEmitter란?
*
* https://edykim.com/ko/post/events-eventemitter-translation-in-node.js/ https://stickie.tistory.com/66 참고
*
* 노드에서는 대부분의 이벤트를 비동기 방식으로 처리
* EventEmitter는 이벤트를 보내고 받을수 있는 기능을 가지고 있음
*
*/
/**
* EventEmitter.prototype에서 app에 복사한 프로퍼티
*
* _events
* _eventsCount
* _maxListeners
* setMaxListeners
* getMaxListeners
* emit
* addListener
* on
* prependListener
* once
* prependOnceListener
* removeListener
* off
* removeAllListeners
* listeners
* rawListeners
* listenerCount
* eventNames
*
*/
/**
* 현재 express에서 사용중인것으로 추정되는 메소드
*
* emit -> 등록한 이벤트를 호출
* on -> 리스너 등록시 사용
*
*/
/**
* EventEmitter를 상속받지 않은 이유
*
* app의 경우 함수이므로 EventEmitter를 상속받기보다는 필요한 프로퍼티를 복사하는것이 더 나을것으로 추정
*
*/
/**
* express에서 EventEmitter의 프로퍼티를 복사하는 이유
*
* 비동기적인 이벤트 처리를 위해 복사하는것으로 추정
*/
mixin(app, proto, false);
// expose the prototype that will get set on requests
app.request = Object.create(req, {
app: { configurable: true, enumerable: true, writable: true, value: app }
})
// expose the prototype that will get set on responses
app.response = Object.create(res, {
app: { configurable: true, enumerable: true, writable: true, value: app }
})
app.init();
return app;
}
/*!
* merge-descriptors
* Copyright(c) 2014 Jonathan Ong
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict'
/**
* Module exports.
* @public
*/
module.exports = merge
/**
* Module variables.
* @private
*/
var hasOwnProperty = Object.prototype.hasOwnProperty
/**
* Object.create(null)을 통해 개체를 만든경우 데이터 타입은 개체이지만 prototype이 undefined로 설정이 됨
* 따라서 hasOwnProperty()함수에 접근할 수 없다.
*
* 또한 자바스크립트의 경우 hasOwnProperty 프로퍼티를 보호하지 않는다.
* 따라서 해당 프로퍼티를 얼마든지 수정할 수 있다.
*
* https://stackoverflow.com/questions/12017693/why-use-object-prototype-hasownproperty-callmyobj-prop-instead-of-myobj-hasow 참고
*/
/**
* hasOwnProperty : 개체가 특정 프로퍼티를 소유하고 있는지 판단하는데 사용한다. / 개체의 프로토타입 체인을 확인하지 않는다.
*/
/**
* Merge the property descriptors of `src` into `dest`
*
* @param {object} dest Object to add descriptors to
* @param {object} src Object to clone descriptors from
* @param {boolean} [redefine=true] Redefine `dest` properties with `src` properties
* @returns {object} Reference to dest
* @public
*/
function merge (dest, src, redefine) {
if (!dest) {
throw new TypeError('argument dest is required')
}
if (!src) {
throw new TypeError('argument src is required')
}
if (redefine === undefined) {
// Default to true
redefine = true
}
/**
* merge-descriptors함수를 사용하기 위해서는 기본적으로 인자 두개를 넣어주어야함
* redefine의 경우 디폴트 값은 true로 설정한다.
*/
/**
* src에 있는 프로퍼티가 dest에도 있는경우
* redefine이 true이면 src에 있는 프로퍼티를 dest로 복사한다.
* redefine이 false이면 src에 있는 프로퍼티를 dest로 복사하지 않는다.
*/
Object.getOwnPropertyNames(src).forEach(function forEachOwnPropertyName (name) {
if (!redefine && hasOwnProperty.call(dest, name)) {
/**
* Function.prototype.call : 첫번째 매개변수를 this, 나머지 매개변수를 인수로 하여 함수를 호출한다.
*/
// Skip descriptor
return
}
/**
* redefine이 false이고 dest에 src의 프로퍼티와 동일한 프로퍼티가 있는경우
* 복사를 하지 않는다.
*/
// Copy descriptor
var descriptor = Object.getOwnPropertyDescriptor(src, name)
/**
* Object.getOwnPropertyDescriptor : 주어진 개체의 프로퍼티에 대한 속성 설명자(descriptor)를 반환한다.
*/
Object.defineProperty(dest, name, descriptor)
/**
* Object.defineProperty : 개체에 직접 새로운 속성을 정의하거나 이미 존재하는 속성을 수정한 후, 그 개체를 반환한다.
*/
/**
* src의 프로퍼티를 dest에 복사한다.
*/
})
return dest
}
https://github.com/JsTsPractices/express/commit/e7c9be5eede3286ff52b7d06e6239f56ed9af7f3