세리프 따라잡기
nodejs 객체와 모듈에 대해 본문
1. 자바 스크립트의 문법 중 하나인 객체(object)에 대해 알아보자.
객체(Object) | 배열(Array) | |
공통점 | 이 둘은 정보를 정리·정돈하는 수납 상자라고 생각하면 된다. | |
차이점 | - 순서가 없는 정보를 저장하기에 최적화 됐다. - 숫자로 식별자로 주는 것이 아닌, 이름으로 식별자를 줄 수 있다. |
- 순서에 따라서 정리를 한다. - 각각의 정보들은 고유한 식별자가 있고, 그 식별자는 숫자이다. |
// 배열 예시
var members = ['malgun', 'gothic', 'tistory']; //배열 안에 정보가 담긴 것, 그냥 순서대로 데이터를 넣으면 된다.
console.log(members[1]); //gothic 출력
// 객체 예시
var roles = { //배열의 리터럴은 대괄호, 객체는 중괄호이다.
'programmer': 'malgun',
'designer': 'gothic',
'manager': 'tistory'
}; //객체는 데이터를 그냥 넣는 것이 아닌, 각각의 데이터마다 고유한 이름을 준다.
console.log(roles.designer); //gothic 출력 + 객체는 부를 때 .을 찍어서 부른다.
2. 이번엔 객체에 담겨 있는 데이터를 하나씩 꺼내와서 반복문으로 처리하는 방법을 알아보자. (while, for문)
// 배열
var members = ['malgun', 'gothic', 'tistory'];
console.log(members[1]);
var i = 0;
while (i < members.length) {
console.log('array loop:', members[i]); //'array loop:' 부분은 출력에서 구분하려고. 의미는 X.
i += 1;
}
// 객체
var roles = {
'programmer': 'malgun',
'designer': 'gothic',
'manager': 'tistory'
};
console.log(roles.designer); //객체에 대한 정보를 가져올때, .key값을 적어도 되지만, 배열처럼 roles['designer']라고 해도 된다.
for(var name in roles){ //객체는 어떻게 루프와 함께 사용하는지: for문 처음엔 변수(객체의 식별자=key 가 들어오도록 약속됨)를, in 이라는 약속된 키워드(value)를 꼭 써줘야 한다. 반복적으로 처리하려고 하는 객체를 in 부분에 넣어준다.
console.log('object:', name, 'value:', roles[name]); //'object:'와 'value:'는 구분을 위함(의미X) + value를 얻기위한 코드 추가= roles[키]를 하면, 그 키에 해당되는 정보를 가지고 온다.
} // 정상 출력~
3. 객체 지향 프로그래밍(Object Oriented Programming)의 스타일, 기능들을 살펴보자.
- 값으로서의 함수
var f=function () { //함수는 처리해야 할 일에 대한 정보를 담고 있는 일종의 구문이면서 동시에 값이다. 함수를 변수에 넣을 수 있다면 = 값이다.
console.log(1 + 1);
console.log(1 + 2);
}
console.log(f);
f(); //변수 f를 함수로 하고 실행시키면 된다. = 즉 값이다.
// var i= if(true){console.log(1)}; //js에선 조건문이라는 구문이 값이 아니라서 오류가 난다.
// var w = while(true){console.log(1)}; //while 구문 또한 값이 될 수 없어서 오류가 난다.
var f = function () {
console.log(1 + 1);
console.log(1 + 2);
} //함수는 서로 연관된 데이터를 그룹핑하는 객체
var a=[f]; //배열에 f라는 원소가 담겼는데, 이 f=함수이다.
a[0](); //이렇게 하면 f가 되고 f는 함수기 때문에 2, 3이 출력된다.
//즉 배열의 원소로서 함수가 존재할 수 있다.
var o = {
func:f
} //객체의 원소(프로퍼티)로 f를 주고
o.func(); //이렇게 코드를 쓰면 func:f가 실행되고 f는 함수이기 때문에 2,3이 출력된다.
//즉 js에선 배열과 객체 모두 연관된 데이터를 담는 그릇인데, 처리방법을 그룹핑하는 함수조차도 데이터라 배열, 객체에 담을 수 있다.
보통 함수를 배열보다는 객체에 많이 담는다. 이름을 정해주기 때문에 꺼내기가 좋기 때문이다.
- 데이터와 처리 방법을 담는 그릇으로서 객체
//1억줄이 넘는 코드를 프로젝트하고 있다고 생각해보자~
/*
var v1 = 'v1'; 라고 할때 다른 사람이
~100,000,000 code~
v1 = 'gothic'; 이다 라고 정의 해버리면 = v1이 gothic이라고 출력되는 상황이 벌어짐. 이걸 해결해주는게 객체.
var v2 = 'v2';
*/
var p = { //연관된 것들을 정리하기.
v1: 'v1',
v2: 'v2', //이렇게 v1, v2를 담아주면 문제없다!
f1: function () { //아래의 f1, f2 함수를 이렇게 객체로 정리해준다.
console.log(this.v1); //처음엔 변수 o 여서 o.v1이라고 호출했는데, 변수가 후에 바뀔 수가 있다. 이럴땐 아래 계속
},
f2: function () {
console.log(this.v2); //함수와 같은 함수가 객체 안에서 사용될 때 참조할 수 있는 키워드(this)를 써준다.
},
}
/*
function f1(){
console.log(o.v1);
}
function f1(){
~code~
}
function f2(){
console.log(o.v2);
} f1, f2라는 함수를 정의하고 쓰는데, 누군가 f1이라는 똑같은 함수를 사용했을 때! 이 또한 객체를 이용해 객체의 멤버로 해주면 된다.
*/
p.f1();
p.f2();
이렇듯 객체는 서로 연관된 것들을 정리해주고 그룹핑을 통해 코드의 복잡성을 획기적으로 낮추는 역할을 해준다!
4. template 기능 정리정돈하기.
var http = require('http');
var fs = require('fs');
var url = require('url');
var qs = require('querystring');
var template = { //templateㅁㅁ이라고 적혀있던 함수들을 정리해준다.
html: function (title, list, body, control) { //객체에 있는 값 하나하나를 property(프로퍼티)라고 한다.
return `
<!doctype html>
<html>
<head>
<title>WEB1 - ${title}</title>
<meta charset="utf-8">
</head>
<body>
<h1><a href="/">WEB</a></h1>
${list}
${control}
${body}
</body>
</html>
`;
},
list: function (filelist) {
var list = '<ul>';
var i = 0;
while (i < filelist.length) {
list = list + `<li><a href="/?id=${filelist[i]}">${filelist[i]}</a></li>`;
i = i + 1;
}
list = list + '</ul>';
return list;
}
} //정리를 해주었으니, 아래에서 templateㅁㅁ을 이용해 짠 코드들을 다시 수정해준다.
var app = http.createServer(function (request, response) {
var _url = request.url;
var querydata = url.parse(_url, true).query;
var pathname = url.parse(_url, true).pathname;
if (pathname === '/') {
if (querydata.id === undefined) {
fs.readdir('./data', function (err, filelist) {
var title = 'Welcome';
var description = 'Hello, Node.js';
var list = template.list(filelist); //templatelist → template.list로 호출. 아래의 html도 수정.
var html = template.html(title, list, `<h2>${title}</h2>${description}`, `<a href="/create">create</a>`); //template로 쓰던 변수 이름을 html로 바꿔주고
response.writeHead(200);
response.end(html); //template가 아닌 html로 수정.
}) //홈페이지 부분 수정. 성공했다면 정상 출력이 된다. 그렇다면 이후 templateㅁㅁ들을 다 수정해주면 된다.
} else {
fs.readdir('./data', function (err, filelist) {
fs.readFile(`data/${querydata.id}`, 'utf8', function (err, description) {
var title = querydata.id;
var list = template.list(filelist);
var html = template.html(title, list,
`<h2>${title}</h2>${description}`,
`<a href="/create">create</a> <a href="/update?id=${title}">update</a>
<form action="delete_process" method="post">
<input type="hidden" name="id" value="${title}">
<input type="submit" value="delete">
</form>`);
response.writeHead(200);
response.end(html);
});
});
}
} else if (pathname === '/create') {
fs.readdir('./data', function (err, filelist) {
var title = 'WEB - create';
var list = template.list(filelist);
var html = template.html(title, list,
`<form action="create_process" method="POST">
<p><input type="text" name="title" placeholder="title"></p>
<p>
<textarea name="description" placeholder="description"></textarea>
</p>
<p>
<input type="submit">
</p>
</form>`, '');
response.writeHead(200);
response.end(html);
});
} else if(pathname === '/create_process'){
var body = '';
request.on('data', function(data){
body += data;
});
request.on('end', function(){
var post = qs.parse(body);
var title = post.title;
var description = post.description;
fs.writeFile(`data/${title}`, description, 'utf8', function(err){
response.writeHead(302, {location: `/?id=${title}`});
response.end();
});
});
} else if(pathname === '/update'){
fs.readdir('./data', function (err, filelist) {
fs.readFile(`data/${querydata.id}`, 'utf8', function (err, description) {
var title = querydata.id;
var list = template.list(filelist);
var html = template.html(title, list,
`
<form action="update_process" method="POST">
<input type="hidden" name="id" value="${title}">
<p><input type="text" name="title" placeholder="title" value="${title}"></p>
<p>
<textarea name="description" placeholder="description">${description}</textarea>
</p>
<p>
<input type="submit">
</p>
</form>`, `<a href="/create">create</a> <a href="/update?id=${title}">update</a>`);
response.writeHead(200);
response.end(html);
});
});
} else if(pathname === '/update_process'){
var body = '';
request.on('data', function(data){
body += data;
});
request.on('end', function(){
var post = qs.parse(body);
var id = post.id;
var title = post.title;
var description = post.description;
fs.rename(`data/${id}`, `data/${title}`, function(err){
fs.writeFile(`data/${title}`, description, 'utf8', function(err){
response.writeHead(302, {location: `/?id=${title}`});
response.end();
});
})
});
} else if(pathname === '/delete_process'){
var body = '';
request.on('data', function(data){
body += data;
});
request.on('end', function(){
var post = qs.parse(body);
var id = post.id;
fs.unlink(`data/${id}`, function(err){
response.writeHead(302, {location: `/`});
response.end();
})
});
} else {
response.writeHead(404);
response.end('not found');
};
});
app.listen(3000); //성공적으로 정리가 되었다면 이전과 같이 잘 동작하는 것을 볼 수 있다.
이 코드들이 이전과 비교해 동작 방법이 다르지 않다(똑같다). 동작 방법은 유지하면서 내부의 코드를 더 효율적으로 바꾸는 행위를 리펙토링(refactoring)이라고 한다. 처음부터 함수, 객체와 같은 코드를 짜는 것은 쉬운 일이 아니다. 우리가 알고 있는 최소한의 문법으로 투박하더라도 잘 동작이 된다면, 그 뒤에 반복되는 코드들을 다시 보며 자주 리펙토링을 하는 게 좋다. (처음부터 이상적인 코드를 짜려고 하면 한 줄도 안 짜질 수 있다.)
5. 모듈(Module)
정리정돈 하는 객체가 많아지면 이런 객체를 또 정리정돈할 수 있는 더 큰 틀의 도구가 모듈이다.
- 형식
// file name: mpart일 때, 아래 코드는 mpart에 쓴 내용
var m = { //객체, 함수가 많다고 가정해보자.
v:'v',
f:function(){
console.log(this.v);
}
}
module.exports = m; //우리가 만들고 있는 모듈이 담겨있는 mpart.js에 여러 기능들 중 m이 가리키는 저 객체를 모듈 바깥에서 사용할 수 있도록 exports하겠다는 의미.
// file name: 2일 때, 아래는 2 file의 내용.
var part = require('./mpart.js') //가져올때 require를 쓴다.
// console.log(part); - 확인 작업. part라는 변수는 모듈을 로딩한 결과가 담겨있고, 이 안에는 mpart에서 모듈로 한 객체들이 담겨있다.
part.f(); //f에 담긴 것 꺼내기. v 출력.
- 활용 (위의 4번에서 한 var template = 에 해당하는 부분을 새로운 파일 lib/template.js에 옮겨 모듈로 실행)
// lib/template.js에 속한 파일
module.exports = { //이렇게 써줘도 모듈을 외부로 보낼 수 있다.
html: function (title, list, body, control) {
return `
<!doctype html>
<html>
<head>
<title>WEB1 - ${title}</title>
<meta charset="utf-8">
</head>
<body>
<h1><a href="/">WEB</a></h1>
${list}
${control}
${body}
</body>
</html>
`; //title 부분의 web1 부분을 수정해 잘 동작되는지 체크 = 잘 된다!
},
list: function (filelist) {
var list = '<ul>';
var i = 0;
while (i < filelist.length) {
list = list + `<li><a href="/?id=${filelist[i]}">${filelist[i]}</a></li>`;
i = i + 1;
}
list = list + '</ul>';
return list;
}
}
* lib = library의 줄임말 (폴더명)
// 이전에 길었던 부분을 lib/template.js에 잘라넣고, 이곳의 코드는 간편하게 바꿔준다.
var template = require('./lib/template.js'); //모듈 불러오기.
이렇게 해주고 잘 동작하는지 확인해주면, 메인 파일이 정상 실행이 되는 것을 볼 수 있다.
'Node.js' 카테고리의 다른 글
nodejs-express 설치, helloworld 출력 및 코드 의미, 홈·상세 페이지 구현, (0) | 2021.01.12 |
---|---|
nodejs의 보안(입·출력)과 API에 대해, 끝으로…. (0) | 2021.01.11 |
nodejs app제작(전송 데이터 받기), 파일생성과 리다이렉션, 글 수정 및 삭제 버튼 구현 (0) | 2021.01.07 |
nodejs에서 동기와 비동기, callback, 패키지 매니저(pm2), html form, 글쓰기 ui 생성 (0) | 2021.01.06 |
nodejs에서 파일 목록 알아내기, 글 목록 출력하기, 함수 문법 (0) | 2021.01.05 |
Comments