app.set = function set(setting, val) {
if (arguments.length === 1) {
// app.get(setting)
return this.settings[setting];
}
debug('set "%s" to %o', setting, val);
// trigger matched settings
switch (setting) {
case "etag":
this.set("etag fn", compileETag(val));
break;
case "query parser":
this.set("query parser fn", compileQueryParser(val));
break;
case "trust proxy":
this.set("trust proxy fn", compileTrust(val));
// trust proxy inherit back-compat
Object.defineProperty(this.settings, trustProxyDefaultSymbol, {
configurable: true,
value: false, <- trustProxyDefaultSymbol의 값을 false로 설정한다.
});
break;
}
return this;
};
app.defaultConfiguration = function defaultConfiguration() {
var env = process.env.NODE_ENV || "development";
// default settings
this.enable("x-powered-by");
this.set("etag", "weak");
this.set("env", env);
this.set("query parser", "extended");
this.set("subdomain offset", 2);
this.set("trust proxy", false); <- trustProxyDefaultSymbol를 false로 설정
// trust proxy inherit back-compat
Object.defineProperty(this.settings, trustProxyDefaultSymbol, {
configurable: true,
value: true, <- trustProxyDefaultSymbol를 true로 설정
});
debug("booting in %s mode", env);
this.on("mount", function onmount(parent) {
// inherit trust proxy
if (
this.settings[trustProxyDefaultSymbol] === true &&
typeof parent.settings["trust proxy fn"] === "function"
) {
delete this.settings["trust proxy"];
delete this.settings["trust proxy fn"];
}
// inherit protos
setPrototypeOf(this.request, parent.request);
setPrototypeOf(this.response, parent.response);
setPrototypeOf(this.engines, parent.engines);
setPrototypeOf(this.settings, parent.settings);
});
// setup locals
this.locals = Object.create(null);
// top-most app is mounted at /
this.mountpath = "/";
// default locals
this.locals.settings = this.settings;
// default configuration
this.set("view", View);
this.set("views", resolve("views"));
this.set("jsonp callback name", "callback");
if (env === "production") {
this.enable("view cache");
}
Object.defineProperty(this, "router", {
get: function () {
throw new Error(
"'app.router' is deprecated!\nPlease see the 3.x to 4.x migration guide for details on how to update your app."
);
},
});
};
this.on("mount", function onmount(parent) {
// inherit trust proxy
if (
this.settings[trustProxyDefaultSymbol] === true &&
typeof parent.settings["trust proxy fn"] === "function"
) {
delete this.settings["trust proxy"];
delete this.settings["trust proxy fn"];
}
// inherit protos
setPrototypeOf(this.request, parent.request);
setPrototypeOf(this.response, parent.response);
setPrototypeOf(this.engines, parent.engines);
setPrototypeOf(this.settings, parent.settings);
});
express/lib/application.js
app.defaultConfiguration = function defaultConfiguration() {
var env = process.env.NODE_ENV || "development";
// default settings
this.enable("x-powered-by");
this.set("etag", "weak");
this.set("env", env);
this.set("query parser", "extended");
this.set("subdomain offset", 2);
this.set("trust proxy", false);
// trust proxy inherit back-compat
Object.defineProperty(this.settings, trustProxyDefaultSymbol, {
configurable: true,
value: true,
});
debug("booting in %s mode", env);
/**
* mount 이벤트
*
* const express = require("express");
* const app = express();
* const admin = express();
* app.use("/admin", admin); <- 마운트 이벤트 발생
*/
this.on("mount", function onmount(parent) {
// inherit trust proxy
if (
this.settings[trustProxyDefaultSymbol] === true &&
typeof parent.settings["trust proxy fn"] === "function"
) {
delete this.settings["trust proxy"];
delete this.settings["trust proxy fn"];
}
/**
* trust proxy가 default로 설정되어 있는 경우
* 해당 설정을 지운다.
*/
// inherit protos
/**
* 부모의 프로퍼티를 자식의 프로퍼티의 프로토타입으로 설정한다.
*/
setPrototypeOf(this.request, parent.request);
setPrototypeOf(this.response, parent.response);
setPrototypeOf(this.engines, parent.engines);
setPrototypeOf(this.settings, parent.settings);
/**
* 개체와 프로토타입에 동일한 이름의 프로퍼티가 설정되어 있는 경우
* 자식 프로퍼티를 우선한다.
*
* setPrototypeOf를 이용하여 부모의 프로퍼티를 자식의 프로퍼티의 프로토타입으로 설정한 이유는
* 자식의 프로퍼티에 설정된 값이 있다면 자식의 값을 우선적으로 사용할수 있도록 하기위한것이 아닐까 추측
*/
});
// setup locals
this.locals = Object.create(null);
/**
* hasOwnProperty등의 기본 메서드조차 없는 개체를 생성한다.
*/
// top-most app is mounted at /
this.mountpath = "/";
/**
* 위의 설정을 통해 마운트 이벤트가 정확하게 어떤 이벤트인지 감을 잡을 수 있는것 같다.
*/
// default locals
this.locals.settings = this.settings;
// default configuration
this.set("view", View);
this.set("views", resolve("views"));
this.set("jsonp callback name", "callback");
if (env === "production") {
this.enable("view cache");
}
Object.defineProperty(this, "router", {
get: function () {
throw new Error(
"'app.router' is deprecated!\nPlease see the 3.x to 4.x migration guide for details on how to update your app."
);
},
});
};
setPrototypeOf/index.js
"use strict";
/* eslint no-proto: 0 */
module.exports =
Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array ? setProtoOf : mixinProperties);
/**
* Object.setPrototypeOf가 (null || undefined)등이 아닌경우 Object.setPrototypeOf를 사용한다.
* Object.setPrototypeOf가 (null || undefined)인 경우 __proto__프로퍼티가 개체의 프로토타입을 변경할수 있는지 여부를 통하여 결정한다.
*/
/**
* { __proto__: [] } 의 프로토타입
* 1. 개체 리터럴로 선언하였으므로 프로토타입은 Object이다.
* 2. __proto__프로퍼티를 배열 리터럴로 선언하였으므로 __proto__는 배열이다.
* 3. 만약 __proto__의 값 변경을 통해 프로토타입을 변경할 수 있다면, { __proto__: [] }의 프로토타입은 배열이 될것이다.
* 4. 만약 __proto__의 값을 변경하더라도 프로토타입을 변경할 수 없다면, { __proto__: [] }의 프로토타입은 개체가 될것이다.
*/
/**
* __proto__프로퍼티 변경을 통한 프로토타입 변경 가능여부를 확인해야하는 이유
*
* 1. __proto__는 es6이전에 표준이 아니었다.
* 2. es6를 통한 __proto__프로퍼티의 표준화 작업을 통해, __proto__프로퍼티를 통한 프로토타입 변경을 할 수 없게되었다.
*
* https://2ality.com/2015/09/proto-es6.html 참고
* https://levelup.gitconnected.com/the-mysterious-javascript-objects-proto-property-67b7c6b3140c 참고
*/
/**
* __proto__를 통하여 프로토타입 자체를 변경한다.
*/
function setProtoOf(obj, proto) {
obj.__proto__ = proto;
return obj;
}
/**
* __proto__를 통한 프로토타입 변경이 힘든경우
* proto의 프로퍼티중 obj에 없는 프로퍼티만 복사한다.
*/
function mixinProperties(obj, proto) {
for (var prop in proto) {
if (!Object.prototype.hasOwnProperty.call(obj, prop)) {
obj[prop] = proto[prop];
}
}
return obj;
}