<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>_upper.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Tue, 14 Nov 2023 05:16:47 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. _upper.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/_upper" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Node.js 섹션 8 노드버드 SNS 만들기
]]></title>
            <link>https://velog.io/@_upper/Node.js-%EC%84%B9%EC%85%98-8-%EB%85%B8%EB%93%9C%EB%B2%84%EB%93%9C-SNS-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@_upper/Node.js-%EC%84%B9%EC%85%98-8-%EB%85%B8%EB%93%9C%EB%B2%84%EB%93%9C-SNS-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Tue, 14 Nov 2023 05:16:47 GMT</pubDate>
            <description><![CDATA[<h2 id="프로젝트-구조-갖추기">프로젝트 구조 갖추기</h2>
<p>npm init하고 버전을 0.0.1로 최소한의 버전을 사용 -&gt; 버전을 더 많이 쓰기 위해서</p>
<h4 id="sqlize-관련된-것-3개의-라이브러이-다운">SQlize 관련된 것 3개의 라이브러이 다운</h4>
<pre><code>npm i sequelize mysql2 sequelize-cli</code></pre><p>mysql2: Node와 MySQL DB를 연결해주는 드라이버</p>
<h4 id="sqlize-초반-세팅">SQLize 초반 세팅</h4>
<pre><code>npx sequelize init</code></pre><h4 id="nodebird-폴더-구조">nodebird 폴더 구조</h4>
<p><img src="https://velog.velcdn.com/images/_upper/post/72334b62-fa98-4916-87c3-b72feb0d4e8e/image.png" alt="">
Public: 프론트에서 가져다 쓸 이미또는 css 자바스크립트 html 정적리소스
passport: 로그인을 도와줄 라이브러리
views: 넌적스 화면
routes: 라우터드을 담당
.env: 설정 파일</p>
<h4 id="익스프레스-관련-라이브러리-설치">익스프레스 관련 라이브러리 설치</h4>
<pre><code>npm i express cookie-parser express-session morgan multer dotenv nunjucks</code></pre><h4 id="개발용-서버">개발용 서버</h4>
<pre><code>npm i -D nodemon</code></pre><h4 id="appjs">app.js</h4>
<p>메인 파일</p>
<pre><code>const express = require(&#39;express&#39;);
const cookieParser = require(&#39;cookie-parser&#39;);
const morgan = require(&#39;morgan&#39;);
const path = require(&#39;path&#39;);
const session = require(&#39;express-session&#39;);
const nunjucks = require(&#39;nunjucks&#39;);
const dotenv = require(&#39;dotenv&#39;);

dotenv.config();
const pageRouter = require(&#39;./routes/page&#39;);

const app = express();
app.set(&#39;port&#39;, process.env.PORT || 8001);
app.set(&#39;view engine&#39;, &#39;html&#39;);
nunjucks.configure(&#39;views&#39;, {
  express: app,
  watch: true,
});

app.use(morgan(&#39;dev&#39;));
app.use(express.static(path.join(__dirname, &#39;public&#39;)));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser(process.env.COOKIE_SECRET));
app.use(session({
  resave: false,
  saveUninitialized: false,
  secret: process.env.COOKIE_SECRET,
  cookie: {
    httpOnly: true,
    secure: false,
  },
}));

app.use(&#39;/&#39;, pageRouter);

app.use((req, res, next) =&gt; {
  const error =  new Error(`${req.method} ${req.url} 라우터가 없습니다.`);
  error.status = 404;
  next(error);
});

app.use((err, req, res, next) =&gt; {
  res.locals.message = err.message;
  res.locals.error = process.env.NODE_ENV !== &#39;production&#39; ? err : {};
  res.status(err.status || 500);
  res.render(&#39;error&#39;);
});

app.listen(app.get(&#39;port&#39;), () =&gt; {
  console.log(app.get(&#39;port&#39;), &#39;번 포트에서 대기중&#39;);
});


</code></pre><hr>
<h2 id="데이터베이스-세팅하기">데이터베이스 세팅하기</h2>
<p>모델 기본 구성방식</p>
<pre><code>const Sequelize = require(&#39;sequelize&#39;);

class User extends Sequelize.Model {
  static initiate(sequelize) {

  }

  static associate(db) {
}

module.exports = User;</code></pre><p>post.js: 게시글
hashta.js: 해시태그
user.js</p>
<h2 id="passport-세팅-및-회원가입-만들기">passport 세팅 및 회원가입 만들기</h2>
<pre><code>app.use(passport.intialize());</code></pre><p>반드시 express session 아래에 작성해야 함</p>
<p>패스포트에 필요한 미들웨어 하고 따로 패스포트 설정을 해야 한다.</p>
<p>middelswares/index.js</p>
<pre><code>exports.isLoggedIn = (req, res, next) =&gt; {
    if (req.isAuthenticated()) {
      next();
    } else {
      res.status(403).send(&#39;로그인 필요&#39;);
    }
  };
</code></pre><p>패스포트 통해서 로그인 했으면 다음으로 넘어가고 패스포트 통해서 로그인 안 했으면 로그인해라</p>
<h2 id="passport로-이메일-로그인-만들기">passport로 이메일 로그인 만들기</h2>
<p>serializeUser는 사용자 정보 객체에서 아이디만 추려 세션에 저장하는 것
deserializeUser는 세션에 저장한 아이디를 통해 사용자 정보 객체를 불러오는 것</p>
<ol>
<li>/auth/login 라우터를 통해 로그인 요청이 들어옴</li>
<li>라우터에서 passport.authenticate 메서드 호출</li>
<li>로그인 전략(LocalStrategy) 수행</li>
<li>로그인 성공 시 사용자 정보 객체와 함께 req.login 호출</li>
<li>req.login 메서드가 passport.serializeUser 호출</li>
<li>req.session에 사용자 아이디만 저장해서 세션 생성</li>
<li>express session에 설정한 대로 브라우저에 connect.sid 세션 쿠키 전송</li>
<li>로그인 완료</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Node.js 섹션 6 MySQL]]></title>
            <link>https://velog.io/@_upper/Node.js-%EC%84%B9%EC%85%98-6-MySQL</link>
            <guid>https://velog.io/@_upper/Node.js-%EC%84%B9%EC%85%98-6-MySQL</guid>
            <pubDate>Tue, 07 Nov 2023 08:46:12 GMT</pubDate>
            <description><![CDATA[<h2 id="mysql-설치하기">MYSQL 설치하기</h2>
<h3 id="데이터베이스란">데이터베이스란</h3>
<h4 id="지금까지는-데이터를-서버-메모리에-저장했음">지금까지는 데이터를 서버 메모리에 저장했음</h4>
<ul>
<li>서버를 재시작하면 데이터 사라져버림 -&gt; 영구적으로 저장할 공간 필요</li>
</ul>
<h4 id="mysql-관계형-데이터베이스-사용">MySQL 관계형 데이터베이스 사용</h4>
<ul>
<li>데이터베이스: 관련성을 가지며 중복이 없는 데이터들의 집합</li>
<li>DBMS: 데이터베이스를 관리하는 시스템</li>
<li>RDBMS: 관계형 데이터베이스를 관리하는 시스템</li>
<li>서버의 하드 디스크나 SSD 등의 저장 매체에 데이터를 저장</li>
<li>서버 종류 여부와 상관 없이 데이터를 계속 사용할 수 있음</li>
<li>여러 사람이 동시에 접근할 수 있고, 권한을 따로 줄 수 있음</li>
</ul>
<h3 id="mysql-워크벤치-설치하기">mysql, 워크벤치 설치하기</h3>
<h4 id="공식사이트">공식사이트</h4>
<p><a href="https://dev.mysql.com/downloads/installer/">https://dev.mysql.com/downloads/installer/</a></p>
<p>Choosing s Setup Type -&gt; Custom
<img src="https://velog.velcdn.com/images/_upper/post/9fb77791-d637-4bc5-a612-de9706bcffb3/image.png" alt=""></p>
<p>Selecct Products and Features -&gt; server, workbench 추가
<img src="https://velog.velcdn.com/images/_upper/post/14907d08-7f46-40c0-9a8b-cc4d2a3abbf4/image.png" alt=""></p>
<hr>
<h2 id="테이블-만들기">테이블 만들기</h2>
<h3 id="데이터베이스-생성하기">데이터베이스 생성하기</h3>
<h4 id="콘솔에서-mysql-프롬프트에-접속">콘솔에서 MySQL 프롬프트에 접속</h4>
<ul>
<li>CREATE SCHEMA node.js;로 nodejs 데이터베이스 생성</li>
<li>use nodejs;로 생성한 데이터베이스 선택</li>
</ul>
<h3 id="테이블-생성하기">테이블 생성하기</h3>
<h4 id="mysql-프롬프트에서-테이블-생성">MySQL 프롬프트에서 테이블 생성</h4>
<ul>
<li>CREATE TABLE [데이터베이스명.테이블명]으로 테이블 생성</li>
<li>사용자 정보를 저장하는 테이블</li>
</ul>
<h3 id="컬럼과-로우">컬럼과 로우</h3>
<h4 id="나이-결혼-여부-성별같은-정보가-컬럼">나이, 결혼 여부, 성별같은 정보가 컬럼</h4>
<h4 id="실제로-들어가는-데이터는-로우">실제로 들어가는 데이터는 로우</h4>
<p><img src="https://velog.velcdn.com/images/_upper/post/fb244256-5a1c-44e1-ada8-d85f7cff9682/image.png" alt=""></p>
<h3 id="컬럼-옵션들">컬럼 옵션들</h3>
<h4 id="id-int-not-null-auto_increment">id INT NOT NULL AUTO_INCREMENT</h4>
<ul>
<li>INT: 정수 자료형입니다.</li>
<li>VARCHAR: 문자열 자료형입니다. 가변 길이입니다.</li>
<li>TEXT: 문자열 자료형입니다. 고정 길이가 아닙니다.</li>
<li>DATETIME: 날짜와 시간을 나타내는 자료형입니다.</li>
<li>TINYINT: 정수 자료형입니다. -128에서 127까지 저장할 수 있습니다.</li>
<li>NOT NULL: 빈 값을 허용하지 않습니다.</li>
<li>AUTO_INCREMENT: 숫자 자료형인 경우 다음 로우가 저장될 때 자동으로 1씩 증가합니다.</li>
<li>UNSIGNED: 0과 양수만 허용합니다.</li>
<li>ZEROFILL: 숫자의 자리 수가 고정된 경우 빈 자리에 0을 채웁니다.</li>
<li>DEFAULT now(): 날짜 컬럼의 기본값을 현재 시간으로 설정합니다.</li>
</ul>
<hr>
<h2 id="칼럼의-옵션들">칼럼의 옵션들</h2>
<h3 id="댓글-테이블-저장하기">댓글 테이블 저장하기</h3>
<h4 id="commments-테이블-생성">commments 테이블 생성</h4>
<p><img src="https://velog.velcdn.com/images/_upper/post/beaab56d-ba2d-4507-8a3c-1d187f8e90e1/image.png" alt=""></p>
<h3 id="외래키foreign-key">외래키(foreign key)</h3>
<h4 id="댓글-테이블은-사용자-테이블과-관계가-있음사용자가-댓글을-달기-때문">댓글 테이블은 사용자 테이블과 관계가 있음(사용자가 댓글을 달기 때문)</h4>
<ul>
<li>FOREIGN KEY (컬럼명) REFERENCES 데이터베이스.테이블명 (컬럼)</li>
<li>FOREIGN KEY (commenter) REFERENCES nodejs.users (id)</li>
<li>댓글 테이블에는 commenter 컬럼이 생기고 사용자 테이블의 id값이 저장됨</li>
<li>ON DELETE CASCADE, ON UPDATE CASCADE</li>
<li>사용자 테이블의 로우가 지워지고 수정될 때 댓글 테이블의 연관된 로우들도 같이 지워지고 수정됨</li>
<li>데이터를 일치시키기 위해 사용하는 옵션(CASCADE 대신 SET NULL과 NO ACTION도 있음)</li>
</ul>
<h3 id="테이블-목록보기">테이블 목록보기</h3>
<p><img src="https://velog.velcdn.com/images/_upper/post/5b2db763-ea31-411e-b102-5d15272577f9/image.png" alt=""></p>
<hr>
<h2 id="crud-작업하기">CRUD 작업하기</h2>
<h3 id="crud">CRUD</h3>
<h4 id="create-read-update-delete의-두문자어">Create, Read, Update, Delete의 두문자어</h4>
<ul>
<li>데이터베이스에서 많이 하는 작업 4가지</li>
</ul>
<h3 id="create">Create</h3>
<h4 id="insert-into-테이블컬럼명들-values값들">INSERT INTO 테이블(컬럼명들) VALUES(값들)</h4>
<p><img src="https://velog.velcdn.com/images/_upper/post/bb4be5fd-085e-4fb4-bf4c-1e0d2c2af8f1/image.png" alt=""></p>
<h3 id="read">Read</h3>
<h4 id="select-컬럼-from-테이블명">SELECT 컬럼 FROM 테이블명</h4>
<ul>
<li>SELECT * 은 모든 컬럼을 선택한다는 의미<pre><code>SELECT * FROM nodejs.users;</code></pre></li>
<li>컬럼만 따로 추리는 것도 가능<pre><code>SELECT name, married FROM nodejs.users;</code></pre></li>
</ul>
<h3 id="read-옵션들">Read 옵션들</h3>
<h4 id="where로-조건을-주어-선택가능">WHERE로 조건을 주어 선택가능</h4>
<ul>
<li>AND로 여러가지 조건을 동시에 만족하는 것을 찾음<pre><code>SELECT name, age FROM nodejs.users WHERE married = 1 AND age &gt; 30l;</code></pre></li>
<li>OR로 여러가지 조건 중 하나 이상을 만족하는 것을 찾음<pre><code>SELECT id, name FROM nodejs.users WHERE married = 0 OR age &gt; 30;</code></pre><h4 id="order-by로-특정-컬럼-값-순서대로-정렬-가능">ORDER BY로 특정 컬럼 값 순서대로 정렬 가능</h4>
</li>
<li>DESC는 내림차순, ASC는 오름차순<pre><code>SELECT id, name FROM nodejs.users ORDER BY age DESC;</code></pre></li>
</ul>
<h3 id="limit-offset">LIMIT, OFFSET</h3>
<h4 id="limit으로-조회할-개수-제한">LIMIT으로 조회할 개수 제한</h4>
<pre><code>SELECT id, name FROM nodejs.users ORDER BY age DESC LIMIT 1;</code></pre><h4 id="offset으로-앞의-로우들-스킵-가능offset-2면-세-번째-것부터-찾음">OFFSET으로 앞의 로우들 스킵 가능(OFFSET 2면 세 번째 것부터 찾음)</h4>
<pre><code>SELECT id, name FROM nodejs.users ORDER BY age DESC LIMIT 1 OFFSET 1;</code></pre><h3 id="update">Update</h3>
<h4 id="데이터베이스에-있는-데이터를-수정하는-작업">데이터베이스에 있는 데이터를 수정하는 작업</h4>
<ul>
<li>UPDATE 테이블명 SET 컬럼 = 새값 WHERE 조건<pre><code>UPDATE nodejs.users SET comment = &#39;바꿀 내용&#39; WHERE id = 2;</code></pre></li>
</ul>
<h3 id="delete">Delete</h3>
<h4 id="데이터베이스에-있는-데이터를-삭제하는-작업">데이터베이스에 있는 데이터를 삭제하는 작업</h4>
<ul>
<li>DELETE FROM 테이블명 WHERE 조건<pre><code>DELETE FROM nodejs.users WHERE id = 2;</code></pre></li>
</ul>
<hr>
<h2 id="시퀄라이즈-사용하기">시퀄라이즈 사용하기</h2>
<h3 id="시퀄라이즈-orm">시퀄라이즈 ORM</h3>
<h4 id="mysql-작업을-쉽게-할-수-있도록-도와주는-라이브러리">MySQL 작업을 쉽게 할 수 있도록 도와주는 라이브러리</h4>
<ul>
<li>ORM: Object Relational Mapping: 객체와 데이터를 매핑(1대1 짝지음)</li>
<li>MySQL 외에도 다른 RDB(Maria, Postgre, SQLite, MSSQL)와도 호환됨</li>
<li>자바스크립트 문법으로 데이터베이스 조작 가능</li>
</ul>
<h4 id="시퀄라이즈-예제-httpsgithubcomzerochonodejs-booktreemasterch776learn-sequelize">시퀄라이즈 예제: <a href="https://github.com/zerocho/nodejs-book/tree/master/ch7/7.6/learn-sequelize">https://github.com/zerocho/nodejs-book/tree/master/ch7/7.6/learn-sequelize</a></h4>
<ul>
<li>프로젝트 세팅 후, 콘솔을 통해 경로로 이동한 후 package.json 작성</li>
</ul>
<h3 id="시퀄라이즈-cli-사용하기">시퀄라이즈 CLI 사용하기</h3>
<h4 id="시퀄라이즈-명령어-사용하기-위해-sequelize-cli-설치">시퀄라이즈 명령어 사용하기 위해 sequelize-cli 설치</h4>
<ul>
<li>mysql2는 MySQL DB가 아닌 드라이버(Node.js와 MySQL을 이어주는 역할)<pre><code>$ npm i express morgan nunjucks sequelize sequelize-cli mysql2
$ npm i-D nodemon</code></pre><h4 id="npx-sequelize-init으로-시퀄라이즈-구조-생성">npx sequelize init으로 시퀄라이즈 구조 생성</h4>
<pre><code>$ npx sequelize init</code></pre></li>
</ul>
<h3 id="modesindexjs-수정">modes/index.js 수정</h3>
<h4 id="다음과-같이-수정">다음과 같이 수정</h4>
<ul>
<li>require(../config/config) 설정 로딩</li>
<li>new Sequelize(옵션들...)로 DB와 연결 가능</li>
</ul>
<h3 id="mysql-연결하기">MySQL 연결하기</h3>
<h4 id="appjs-작성">app.js 작성</h4>
<ul>
<li>sequelize.sync로 연결</li>
</ul>
<h3 id="연결-테스트하기">연결 테스트하기</h3>
<h4 id="npm-start로-실행해서-select-11-as-result가-나오면-연결-성공">npm start로 실행해서 SELECT 1+1 AS RESULT가 나오면 연결 성공</h4>
<p><img src="https://velog.velcdn.com/images/_upper/post/a1ed4944-75d7-47cc-8896-62cc7d9b07b0/image.png" alt=""></p>
<hr>
<h2 id="시퀄라이즈-모델-만들기">시퀄라이즈 모델 만들기</h2>
<h3 id="모델-옵션들">모델 옵션들</h3>
<h4 id="시퀄라이즈-모델의-자료형은-mysql의-자료형과-조금-다름">시퀄라이즈 모델의 자료형은 MySQL의 자료형과 조금 다름</h4>
<h4 id="define-메서드의-세-번째-인자는-테이블-옵션">define 메서드의 세 번째 인자는 테이블 옵션</h4>
<p>알겠습니다. 사진 속 글자를 똑같이 적어 보겠습니다.</p>
<ul>
<li>timestamps: true면 createdAt(생성 시간), updatedAt(수정 시간) 컬럼을 자동으로 만듦</li>
<li>예제에서는 직접 created_at 컬럼을 만들었으므로 false로 함</li>
<li>paranoid 옵션은 true면 deletedAt(삭제 시간) 컬럼을 만듦, 로우 복구를 위해 완전히 삭제하지 않고 deletedAt에 표시해둠</li>
<li>underscored 옵션은 캐멀케이스로 생성되는 컬럼을 스네이크케이스로 생성</li>
<li>modelName은 모델 이름, tableName 옵션은 테이블 이름을 설정</li>
<li>charset과 collate는 한글 설정을 위해 필요(이모티콘 넣으려면 utf8mb4)</li>
</ul>
<h3 id="댓글-모델-생성하기">댓글 모델 생성하기</h3>
<h4 id="commentjs-생성">comment.js 생성</h4>
<p><img src="https://velog.velcdn.com/images/_upper/post/24ec89f8-374c-4ea3-827d-4ce4fc2ebda3/image.png" alt=""></p>
<h3 id="댓글-모델-활성화하기">댓글 모델 활성화하기</h3>
<h4 id="indexjs에-모델-연결">index.js에 모델 연결</h4>
<ul>
<li>init으로 sequelize와 연결</li>
<li>associate로 관계 설정<pre><code>const Sequelize = require(&#39;sequelize&#39;);
const User = require(&#39;./user&#39;);
const Comment = require(&#39;./comment&#39;);
</code></pre></li>
</ul>
<p>db.sequelize = sequelize;
db.User = User;
db.Comment = Comment;</p>
<p>User.init(sequelize);
Comment.init(sequelize);</p>
<p>User.associate(db);
Comment.associate(db);</p>
<p>module.exports = db;</p>
<pre><code>---

## 테이블 관계 이해하기
### 관계 정의하기
#### users 모델과 comments 모델 간의 관계를 정의

- 1:N 관계 (사용자 한 명이 댓글 여러 개 작성)
- 시퀄라이즈에서는 1:N 관계를 has Many로 표현(사용자.hasMany(댓글))
- 반대의 입장에서는 belongsTo(댓글.belongsTo(사용자))
- belongsTo가 있는 테이블에 컬럼이 생김(댓글 테이블에 commenter 컬럼)

### 1대1 관계
#### 1대1 관계
- 예) 사용자 테이블과 사용자 정보 테이블</code></pre><p>db.User.hasOne(db.Info, { foreignKey: &#39;UserId&#39;, sourcekey: &#39;id&#39; });
db.Info.belongsTo(db.User, { foreignkey: &#39;UserId&#39;, targetKey: &#39;id&#39; });</p>
<pre><code>
### N대N 관계
#### 다대다 관계
- 예) 게시글과 해시태그 테이블
- 하나의 게시글이 여러 개의 해시태그를 가질 수 있고 하나의 해시태그가 여러 개의 게시글을 가질 수 있음
- DB 특성상 다대다 관계는 중간 테이블이 생김</code></pre><p>db.Post.belongsToMany(db.Hashtag, { through: &#39;PostHashtag&#39; });
db.Hashtag.belongsToMany(db.Post, { through: &#39;PostHashtag&#39; });</p>
<pre><code>
---


## 관계 쿼리 알아보기
### 관계 쿼리
#### 결과값이 자바스크립트 객체임</code></pre><p>const user = await User.fingOne({});
console.log(user.nick); // 사용자 닉네임</p>
<pre><code>#### include JOIN 과 비슷한 기능 수행 가능(관계 있는 것 엮을 수 있음)</code></pre><p>const user = await User.findOne({</p>
<pre><code>include: [{

    model: Comment,

}]</code></pre><p>});</p>
<p>console.log(user.Comments); // 사용자 댓글</p>
<pre><code>#### 다대다 모델은 다음과 같이 접근 가능</code></pre><p>db.sequelize.models.PostHashtag</p>
<pre><code>#### get+모델명으로 관계 있는 데이터 로딩 가능</code></pre><p>const user = await User.findOne({});
const comments = await user.getComments();
console.log(comments); // 사용자 댓글</p>
<pre><code>#### as로 모델명 변경 가능</code></pre><p>// 관계를 설정할 때 as로 등록
db.User.hasMany(db.comment, { foreignkey: &#39;commenter&#39;, sourcekey: &#39;id&#39;, as: &#39;Answers&#39; });
// 쿼리할 때는
const user = await User.findOne({});
const comments = await user.getAnswers();
console.log(comments); // 사용자 댓글</p>
<pre><code>#### include나 관계 쿼리 메서드에도 where나 attributes</code></pre><p>const user = await User.findOne({
  include: [{
    model: Comment,
    where: {
      id: 1,
    },
    attributes: [&#39;id&#39;],
  }],
});</p>
<p>// 또는</p>
<p>const comments = await user.getComments({
  where: {
    id: 1,
  },
  attributes: [&#39;id&#39;],
});</p>
<pre><code>#### 생성 쿼리</code></pre><p>const user = await User.findOne({});
const comment = await Comment.create();
await user.addComment(comment);
// 또는
await user.addComment(comment.id);</p>
<pre><code>#### 여러 개를 추가할 때는 배열로 추가 가능</code></pre><p>const user = await User.findOne({});
const comment1 = await Comment.create();
const comment2 = await Comment.create();
await user.addComment([comment1, comment2]);</p>
<pre><code>#### 수정은 set+모델명, 삭제는 remove+모델명

### raw 쿼리
#### 직접 SQL을 쓸 수 있음</code></pre><p>const [result, metadata] = await sequelize.query(&quot;SELECT * from comments&quot;);
console.log(result);</p>
<pre><code>---

## 시퀄라이즈 쿼리 알아보기
### 시퀄라이즈 쿼리 알아보기
#### 윗 줄이 SQL문, 아랫 줄은 시퀄라이즈 쿼리(자바스크립트)
- 특수한 기능들인 경우 Sequelize.Op의 연산자 사용(gt, or 등)
#### 수정</code></pre><p>UPDATE nodejs.users SET comment=&#39;48&#39; WHERE id = 2;
User.update({
    comment: &#39;바꿀 내용&#39;,
}, {
    where: { id: 2 },
});</p>
<pre><code>#### 삭제</code></pre><p>DELETE FROM nodejs.users WHERE id = 2;
User.destroy({
    where: { id: 2 },
});</p>
<pre><code>---

## 시퀄라이즈 실습하기
### 쿼리 수행하기
#### users 라우터
- get, post, delete, patch 같은 요청에 대한 라우터 연결
- 데이터는 JSON 형식으로 응답
- comments 라우터도 마찬가지

### comments 라우터</code></pre><p>const express = require(&#39;express&#39;);
const { User, Comment } = require(&#39;../models&#39;);</p>
<p>const router = express.Router();</p>
<p>router.post(&#39;/&#39;, async (req, res, next) =&gt; {
  try {
    const comment = await Comment.create({
      commenter: req.body.id,
      comment: req.body.comment,
    });</p>
<pre><code>res.status(201).json(comment);</code></pre><p>  } catch (err) {
    console.error(err);
    next(err);
  }
});</p>
<p>router.patch(&#39;/:id&#39;, async (req, res, next) =&gt; {
  try {
    const result = await Comment.update({
      comment: req.body.comment,
    }, { where: { id: req.params.id } });</p>
<pre><code>res.json(result);</code></pre><p>  } catch (err) {
    console.error(err);
    next(err);
  }
});</p>
<p>router.delete(&#39;/:id&#39;, async (req, res, next) =&gt; {
  try {
    const result = await Comment.destroy({ where: { id: req.params.id } });</p>
<pre><code>res.json(result);</code></pre><p>  } catch (err) {
    console.error(err);
    next(err);
  }
});</p>
<p>module.exports = router;</p>
<p>```</p>
<h3 id="서버-접속하기">서버 접속하기</h3>
<h4 id="npm-start로-서버-시작">npm start로 서버 시작</h4>
<ul>
<li>localhost:3000 으로 접속하면 시퀄라이즈가 수행하는 SQL문이 콘솔에 찍힘</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Node.js 섹션 5 익스프레스 웹 서버 만들기]]></title>
            <link>https://velog.io/@_upper/Node.js-%EC%84%B9%EC%85%98-5-%EC%9D%B5%EC%8A%A4%ED%94%84%EB%A0%88%EC%8A%A4-%EC%9B%B9-%EC%84%9C%EB%B2%84-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@_upper/Node.js-%EC%84%B9%EC%85%98-5-%EC%9D%B5%EC%8A%A4%ED%94%84%EB%A0%88%EC%8A%A4-%EC%9B%B9-%EC%84%9C%EB%B2%84-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Tue, 31 Oct 2023 12:18:26 GMT</pubDate>
            <description><![CDATA[<h2 id="express-서버-사용해보기">express 서버 사용해보기</h2>
<h3 id="express-소개">Express 소개</h3>
<h4 id="http-모듈로-웹-서버를-만들-때-코드가-보기-좋지-않고-확장성도-떨어짐">http 모듈로 웹 서버를 만들 때 코드가 보기 좋지 않고, 확장성도 떨어짐</h4>
<ul>
<li>프레임워크로 해결</li>
<li>대표적인 것이 Express(익스프레스), Koa(코아), Hapi(하피)</li>
<li>코드 관리도 용이하고 편의성이 많이 높아짐</li>
</ul>
<h3 id="packagejson-만들기">package.json 만들기</h3>
<h4 id="직접-만들거나-npm-init-명령어-생성">직접 만들거나 npm init 명령어 생성</h4>
<ul>
<li>nodemon이 소스 코드 변경 시 서버를 재시작해줌</li>
</ul>
<h3 id="appjs-작성하기">app.js 작성하기</h3>
<h4 id="서버-구동의-핵심이-되는-파일">서버 구동의 핵심이 되는 파일</h4>
<ul>
<li>app.set(&#39;port&#39;, 포트)로 서버가 실행될 포트 지정</li>
<li>app.get(&#39;주소&#39;, 라우터)로 GET 요청이 올 때 어떤 동작을 할지 지정</li>
<li>app.listen(&#39;포트&#39;, 콜백)으로 몇 번 포트에서 서버를 실행할지 지정</li>
</ul>
<hr>
<h2 id="express로-html-서빙하기">express로 html 서빙하기</h2>
<pre><code>const express = require(&quot;express&quot;);
const path = require(&quot;path&quot;);

const app = express();
app.set(&quot;port&quot;, process.env.PORT || 3000);

app.get(&quot;/&quot;, (req, res) =&gt; {
  // res.send(&#39;Hello, Express&#39;);
  res.sendFile(path.join(__dirname, &quot;/index.html&quot;));
});

app.listen(app.get(&quot;port&quot;), () =&gt; {
  console.log(app.get(&quot;port&quot;), &quot;번 포트에서 대기 중&quot;);
});
</code></pre><hr>
<h2 id="미들웨어-사용하기">미들웨어 사용하기</h2>
<p>Node.js Express의 미들웨어는 웹 애플리케이션의 요청과 응답을 처리하는 중간 단계의 함수이다. </p>
<p>미들웨어는 Express 애플리케이션의 요청 처리 프로세스에서 요청과 응답 객체에 대한 조작 및 처리를 수행하는 역할을 한다.</p>
<p>미들웨어를 사용하여 요청 처리를 여러 단계로 나누고, 각 단계에서 필요한 작업을 수행할 수 있다.</p>
<pre><code>app.use((req, res, next) =&gt; {
    console.log(&#39;모든 요청에 실행하고 싶어요&#39;);
    next();
})

app.get(&#39;*&#39;, (req, res) =&gt; {
  res.send(&#39;hello everybody&#39;);
});

app.get(&#39;/&#39;, (req, res) =&gt; {
  res.sendFile(path.join(__dirname, &#39;index.html&#39;));
});

app.post(&#39;/&#39;, (req, res) =&gt; {
  res.send(&#39;hello express!&#39;);
});

// app.js
const express = require(&#39;express&#39;);
const app = express();

app.get(&#39;/category/javascript&#39;, (req, res) =&gt; {
  res.send(&#39;hello javascript&#39;);
});

app.get(&#39;/category/:name&#39;, (req, res) =&gt; {
  res.send(&#39;hello wildcard&#39;);
});

app.get(&#39;/about&#39;, (req, res) =&gt; {
  res.send(&#39;hello express&#39;);
});

app.get(&#39;*&#39;, (req, res) =&gt; {
  res.send(&#39;hello everybody&#39;);
});

app.listen(3000, () =&gt; {
  console.log(&#39;Server started on port 3000&#39;);
});
</code></pre><h2 id="미들웨어-특성-이해하기">미들웨어 특성 이해하기</h2>
<pre><code>const express = require(&#39;express&#39;);
const path = require(&#39;path&#39;);

const app = express();

app.set(&#39;port&#39;, process.env.PORT || 3000);

app.use((req, res, next) =&gt; {
  console.log(&#39;1 요청에 실행하고싶어요&#39;);
  next();
});

app.get(&#39;/&#39;, (req, res) =&gt; {
  // res.sendFile(path.join(__dirname, &#39;index.html&#39;));
  res.setHeader(&#39;Content-Type&#39;, &#39;text/html&#39;);
  res.status(200).send(&#39;.&#39;);
});

app.post(&#39;/&#39;, (req, res) =&gt; {
  res.send(&#39;hello express!&#39;);
});

</code></pre><h2 id="next-활용법">next 활용법</h2>
<p>next는 Express 미들웨어 함수에서 다음 미들웨어 함수를 호출하기 위한 콜백 함수이다.</p>
<p>Express 미들웨어는 요청과 응답 객체를 조작하고 다음 미들웨어 함수로 제어를 전달할 수 있다. 이때 next 함수를 사용하여 다음 미들웨어 함수를 호출한다.</p>
<h2 id="morgan-bodyparser-cookieparser">morgan, bodyParser, cookieParser</h2>
<h4 id="morgan">Morgan:</h4>
<p>morgan은 Express 애플리케이션의 HTTP 요청 로깅을 도와주는 미들웨어이다. 이를 사용하면 서버에 들어오는 요청에 대한 정보(메서드, URL, 상태 코드, 응답 시간 등)를 쉽게 로깅할 수 있다.</p>
<p>개발 및 디버깅 시에 유용하며, 클라이언트의 요청과 서버의 응답을 추적하는 데 도움이 된다.</p>
<h4 id="body-parser">Body-Parser:</h4>
<p>body-parser는 클라이언트에서 전송된 HTTP 요청의 본문(body)을 파싱하는 역할을 한다.</p>
<p>HTTP POST 요청이나 PUT 요청과 같이 요청 본문에 데이터를 담아 보낼 때, 이 데이터를 파싱하여 JavaScript 객체로 변환해준다. 이렇게 파싱된 데이터를 Express 애플리케이션에서 사용할 수 있다.</p>
<h4 id="cookie-parser">Cookie-Parser:</h4>
<p>cookie-parser는 클라이언트에서 전송된 쿠키를 파싱하는 역할을 한다.</p>
<p>쿠키는 클라이언트와 서버 간의 상태를 유지할 때 사용되며, 이를 파싱하여 JavaScript 객체로 변환해준다. 이후 Express 애플리케이션에서 파싱된 쿠키 데이터를 사용할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Node.js 섹션 4 패키지 매니저]]></title>
            <link>https://velog.io/@_upper/%EC%84%B9%EC%85%98-4-%ED%8C%A8%ED%82%A4%EC%A7%80-%EB%A7%A4%EB%8B%88%EC%A0%80</link>
            <guid>https://velog.io/@_upper/%EC%84%B9%EC%85%98-4-%ED%8C%A8%ED%82%A4%EC%A7%80-%EB%A7%A4%EB%8B%88%EC%A0%80</guid>
            <pubDate>Tue, 31 Oct 2023 10:59:08 GMT</pubDate>
            <description><![CDATA[<h2 id="packagejson">package.json</h2>
<h3 id="npm이란">npm이란</h3>
<h4 id="node-package-manager">Node Package Manager</h4>
<ul>
<li><p>노드의 패키지 매니저</p>
</li>
<li><p>다른 사람들이 만든 소스 코드들을 모아둔 저장소</p>
</li>
<li><p>남의 코드를 사용하여 프로그래밍 가능</p>
</li>
<li><p>이미 있는 기능을 다시 구현할 필요가 없어 효율적</p>
</li>
<li><p>오픈 소스 생태계를 구성중</p>
</li>
<li><p>패키지: npm에 업로드된 노드 모듈</p>
</li>
<li><p>모듈이 다른 모듈을 사용할 수 있듯 패키지도 다른 패키지를 사용할 수 있음</p>
</li>
<li><p>의존 관계라고 부름</p>
</li>
</ul>
<h3 id="packagejson-1">package.json</h3>
<h4 id="현재-프로젝트에-대한-정보와-사용-중인-패키지에-대한-정보를-담은-파일">현재 프로젝트에 대한 정보와 사용 중인 패키지에 대한 정보를 담은 파일</h4>
<ul>
<li>같은 패키지ㅏ도 버전별로 기능이 다를 수 있으므로 버전을 기록해두어야 함</li>
<li>동일한 버전을 설치하지 않으면 문제가 생길 수 있음</li>
<li>노드 프로젝트 시작 전 package.json부터 만들고 시작함(npm init) </li>
</ul>
<h3 id="packagejson-속성들">package.json 속성들</h3>
<ul>
<li>name: 패키지의 이름입니다.</li>
<li>version: 패키지의 버전입니다.</li>
<li>description: 프로젝트 설명입니다.</li>
<li>main: 실행 파일 경로입니다. 이 파일은 Node.js에서 프로젝트를 실행할 때 실행됩니다.</li>
<li>scripts: 프로젝트에서 사용할 수 있는 명령어 목록입니다.</li>
<li>repository: Git 저장소 주소입니다.</li>
<li>keywords: 키워드입니다. 이 키워드를 사용하여 프로젝트를 검 색 할 수 있습니다.</li>
<li>license: 라이선스입니다.</li>
</ul>
<h3 id="npm-스크립트">npm 스크립트</h3>
<h4 id="npm-init이-완료되면-폴더에-packagejson이-생성됨">npm init이 완료되면 폴더에 package.json이 생성됨</h4>
<h4 id="npm-run-스크립트명으로-스트립트-실행">npm run [스크립트명]으로 스트립트 실행</h4>
<h3 id="패키지-설치하기">패키지 설치하기</h3>
<h4 id="express-설치하기">express 설치하기</h4>
<p>npm install express</p>
<h4 id="packagejson에-기록됨dependencies에-express-이름과-버전-추가됨">package.json에 기록됨(dependencies에 express 이름과 버전 추가됨)</h4>
<pre><code>// package.json
{
  &quot;name&quot;: &quot;npmtest&quot;,
  &quot;version&quot;: &quot;1.0.0&quot;,
  &quot;description&quot;: &quot;&quot;,
  &quot;main&quot;: &quot;index.js&quot;,
  &quot;scripts&quot;: {
    &quot;test&quot;: &quot;echo \&quot;Error: no test specified\&quot; &amp;&amp; exit 1&quot;,
    &quot;start&quot;: &quot;node index&quot;
  },
  &quot;author&quot;: &quot;ZeroCho&quot;,
  &quot;license&quot;: &quot;MIT&quot;,
  &quot;dependencies&quot;: {
    &quot;body-parser&quot;: &quot;^1.19.0&quot;,
    &quot;cookie-parser&quot;: &quot;^1.4.5&quot;,
    &quot;express&quot;: &quot;^4.17.1&quot;
  },
  &quot;devDependencies&quot;: {
    &quot;nodemon&quot;: &quot;^2.0.5&quot;
  }
}

</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Node.js 섹션3 http 모듈로 서버 만들기]]></title>
            <link>https://velog.io/@_upper/Node.js-%EC%84%B9%EC%85%983-http-%EB%AA%A8%EB%93%88%EB%A1%9C-%EC%84%9C%EB%B2%84-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@_upper/Node.js-%EC%84%B9%EC%85%983-http-%EB%AA%A8%EB%93%88%EB%A1%9C-%EC%84%9C%EB%B2%84-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Mon, 16 Oct 2023 14:57:39 GMT</pubDate>
            <description><![CDATA[<h2 id="http-서버-만들기">HTTP 서버 만들기</h2>
<h3 id="서버와-클라이언트">서버와 클라이언트</h3>
<h4 id="서버와-클라이언트의-관계">서버와 클라이언트의 관계</h4>
<ul>
<li>클라이언트가 서버로 요청(request)을 보냄</li>
<li>서버는 요청을 처리</li>
<li>처리 후 클라이언트로 응답(response)을 보냄</li>
</ul>
<h3 id="노드로-http-서버-만들기">노드로 http 서버 만들기</h3>
<h4 id="http-요청에-응답하는-노드-서버">http 요청에 응답하는 노드 서버</h4>
<ul>
<li>createServer로 요청 이벤트에 대기</li>
<li>req 객체는 요청에 관한 정보가, res 객체는 응답에 관한 정보가 담겨 있음</li>
</ul>
<h3 id="localhost와-포트">localhost와 포트</h3>
<h4 id="localhost는-컴퓨터-내부-주소">localhost는 컴퓨터 내부 주소</h4>
<ul>
<li>외부에서는 접근 불가능</li>
</ul>
<h4 id="포트는-서버-내에서-프로세스르-구분하는-번호">포트는 서버 내에서 프로세스르 구분하는 번호</h4>
<ul>
<li>기본적으로 http 서버는 80번 포트 사용(생략가능, https는 443)</li>
<li>예) <a href="http://www.gitbut.com:80">www.gitbut.com:80</a> -&gt; <a href="http://www.github.com">www.github.com</a></li>
<li>다른 포트로 데이터베이스나 다른 서버 동시에 연결 가능</li>
</ul>
<hr>
<h2 id="fs로-html-파일-읽어-제공하기">fs로 HTML 파일 읽어 제공하기</h2>
<h5 id="server2js">server2.js</h5>
<p><img src="https://velog.velcdn.com/images/_upper/post/5a11bac7-c508-48ce-92fb-cfb35251ab70/image.png" alt=""></p>
<hr>
<h2 id="rest-api-서버-만들기">REST API 서버 만들기</h2>
<h3 id="rest-api">REST API</h3>
<h4 id="서버에-요청을-보낼-때는-주소를-통해-요청의-내용을-표현">서버에 요청을 보낼 때는 주소를 통해 요청의 내용을 표현</h4>
<ul>
<li>/index.html이면 index.html을 보내달라는 뜻</li>
<li>항상 html을 요구할 필요는 없음</li>
<li>서버가 이해하기 쉬운 주소가 좋음</li>
</ul>
<h4 id="rest-apirespresentational-state-transfer">REST API(Respresentational State Transfer)</h4>
<ul>
<li>서버의 자원을 정의하고 자원에 대한 주소를 지정하는 방법</li>
<li>/user이면 사용자 정보에 관한 정보를 요청하는 것</li>
<li>/post면 게시글에 관련된 자원을 요청하는 것</li>
</ul>
<h4 id="http-요청-메서드">HTTP 요청 메서드</h4>
<ul>
<li>GET: 서버 자원을 가져오라고 할 때 사용</li>
<li>POST: 서버에 자원을 새로 등록하고자 할 때 사용(또는 뭘 써야할지 애매할 때)</li>
<li>PUT: 서버의 자원을 요청에 들어있는 자원으로 치환하고자 할 때 사용</li>
<li>PATCH: 서버 자원의 일부만 수정하고자 할 때 사용</li>
<li>DELETE: 서버의 자원ㅇ르 삭제하고자 할 때 사용</li>
</ul>
<h3 id="http-프로토콜">HTTP 프로토콜</h3>
<h4 id="클라이언트가-누구든-서버와-http-프로토콜로-소통-가능">클라이언트가 누구든 서버와 HTTP 프로토콜로 소통 가능</h4>
<ul>
<li>ios, 안드로이드, 웹이 모두 같은 주소로 요청 보낼 수 있음</li>
<li>서버와 클라이언트으 ㅣ분리</li>
</ul>
<h4 id="restful">RESTful</h4>
<ul>
<li>REST API를 사용한 주소 체계를 이용하는 서버</li>
<li>GET / user는 사용자를 조회하는 요청, POST /user 사용자를 등록하는 요청</li>
</ul>
<h3 id="rest-서버-만들기">REST 서버 만들기</h3>
<h4 id="github-저장소httpsgithubcomzerochonodejs-book-ch4-소스-창조">GitHub 저장소(<a href="https://github.com/zerocho/nodejs-book">https://github.com/zerocho/nodejs-book</a>) ch4 소스 창조</h4>
<h4 id="restserverjs에-주목">restServer.js에 주목</h4>
<ul>
<li><p>GET 메서드에서 /, /about 요청 주소는 페이지를 요청하는 것이므로 HTML 파일을 읽어서 전송합니다. AJAX 요청을 처리하는 /users에서는 users 데이터를 전송합니다. JSON 형식으로 보내기 위해 JSON.stringify를 해주었습니다. 그 외의 GET 요청은 CSS JS 파일을 요청하는 것이므로 찾아서 보내주고, 없다면 404 NOT FOUND 에러를 응답합니다.</p>
</li>
<li><p>POST와 PUT 메서드는 클라이언트로부터 데이터를 받으므로 특별한 처리가 필요합니다. req.on(&#39;data&#39;, 콜백)과 req.on(&#39;end&#39;, 콜백) 부분인데요. 3.6.2절의 버퍼와 스트림에서 배웠던 readStream 입니다. readStream으로 요청과 같이 들어오는 요청 본문을 받을 수 있습니다. 단, 문자열이므로 JSON으로 만드는 JSON.parse 과정이 한 번 필요합니다.</p>
</li>
<li><p>DELETE 메서드로 요청이 오면 주소에 들어 있는 키에 해당하는 사용자를 제거합니다.</p>
</li>
<li><p>해당하는 주소가 없을 경우 404 NOT FOUND 에러를 응답합니다.</p>
</li>
</ul>
<hr>
<h2 id="post-put-delete-요청-보내기">POST, PUT, DELETE 요청 보내기</h2>
<h3 id="rest-서버-실행하기">REST 서버 실행하기</h3>
<h4 id="localhost8085에-접속">localhost:8085에 접속</h4>
<p>콘솔
$ node restServer
8085번 포트에서 서버 대기 중입니다.</p>
<h3 id="rest-요청-확인하기">REST 요청 확인하기</h3>
<h4 id="개발자도구f12-network-탭에서-요청-내용-실시간-확인-가능">개발자도구(F12) Network 탭에서 요청 내용 실시간 확인 가능</h4>
<ul>
<li>Name은 요청 주소, Method는 요청 메서드, Status는 HTTP 응답 코드 </li>
<li>Protocol은 HTTP 프로토콜, Type은 요청 종류(xhr은 AJAX 요청)</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Node.js 섹션1 알아두어야 할 자바스크립트]]></title>
            <link>https://velog.io/@_upper/Node.js-%EC%84%B9%EC%85%981-%EC%95%8C%EC%95%84%EB%91%90%EC%96%B4%EC%95%BC-%ED%95%A0-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%E3%85%8B</link>
            <guid>https://velog.io/@_upper/Node.js-%EC%84%B9%EC%85%981-%EC%95%8C%EC%95%84%EB%91%90%EC%96%B4%EC%95%BC-%ED%95%A0-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%E3%85%8B</guid>
            <pubDate>Mon, 16 Oct 2023 14:13:49 GMT</pubDate>
            <description><![CDATA[<h2 id="화살표-함수">화살표 함수</h2>
<h3 id="add1-add2-add3-add4는-같은-기능을-하는-함수">add1, add2, add3, add4는 같은 기능을 하는 함수</h3>
<ul>
<li>add2: add1을 화살표 함수로 나타낼 수 있음</li>
<li>add3: 함수의 본문이 return만 있는 경우 return 생략</li>
<li>add4: return이 생략된 함수의 본문을 소괄호로 감싸줄 수 있음</li>
<li>not1과 no2도 같은 기능을 함(매개변수 하나일 때 괄호 생략)
<img src="https://velog.velcdn.com/images/_upper/post/e066dd2e-d487-427d-8080-c5d7a8b48d2d/image.png" alt=""></li>
</ul>
<h3 id="화살표-함수가-기존-function-을-대체하는-건-아님this가-달라짐">화살표 함수가 기존 function() {}을 대체하는 건 아님(this가 달라짐)</h3>
<ul>
<li>logFriends 메서드의 this 값에 주목</li>
<li>forEach의 function의 this와 logFriends의 this는 다름</li>
<li>that이라는 중간 변수를 이용해서 logFriends의 this를 전달</li>
</ul>
<h3 id="foreach의-인자로-화살표-함수가-들어간-간-것에-주목">forEach의 인자로 화살표 함수가 들어간 간 것에 주목</h3>
<ul>
<li>forEach의 화살표함수의 this와 logFriends의 this가 같아짐</li>
<li>화살표 함수는 자신을 포함하는 함수의 this를 물려받음</li>
<li>물려받고 싶지 않을 때: function() {}을 사용</li>
</ul>
<hr>
<h2 id="promise-asyncawait">promise, async/await</h2>
<h3 id="콜백-헬이라고-불리는-지저분한-자바스크립트-코드의-해결책">콜백 헬이라고 불리는 지저분한 자바스크립트 코드의 해결책</h3>
<ul>
<li>프로미스: 내용의 실행은 되었지만 결과를 아직 반환하지 않은 객체</li>
<li>Then을 붙이면 결과를 반환함</li>
<li>실행이 완료되지 않았으면 완료된 후에 Then 내부함수가 실행됨</li>
<li>Resolvef(성공리턴값) -&gt; then으로 연결</li>
<li>Reject(실패리턴값) -&gt; catch로 연결</li>
<li>Finally 부분은 무조거 실행됨</li>
</ul>
<h3 id="콜백-패턴3중첩을-프로미스로-바꾸는-예제">콜백 패턴(3중첩)을 프로미스로 바꾸는 예제</h3>
<p><img src="https://velog.velcdn.com/images/_upper/post/c40e3584-f44d-4d24-a9eb-9c1e45a5bdc0/image.png" alt=""></p>
<h3 id="findone-save-메서드가-프로미스를-지원한다고-가정">findOne, save 메서드가 프로미스를 지원한다고 가정</h3>
<p><img src="https://velog.velcdn.com/images/_upper/post/8cdf0f3e-f78f-4bed-878d-4c2faf1f6fcb/image.png" alt=""></p>
<h3 id="promiseresolve성공리턴값-바로-resolve하는-프로미스">Promise.resolve(성공리턴값): 바로 resolve하는 프로미스</h3>
<h3 id="promisereject실패리턴값-바로-reject하는-프로미스">Promise.reject(실패리턴값): 바로 reject하는 프로미스</h3>
<p><img src="https://velog.velcdn.com/images/_upper/post/ca8ab6bf-0a08-4656-81d3-6922b2ccdf92/image.png" alt=""></p>
<h3 id="promiseall배열-여러-개의-프로미스를-동시에-실행">Promise.all(배열): 여러 개의 프로미스를 동시에 실행</h3>
<ul>
<li>하나라도 실패하면 catch로 감</li>
<li>allSettled로 실패한 것만 추려낼 수 있음</li>
</ul>
<h3 id="asyncawait">async/await</h3>
<h4 id="이전-챕터의-프로미스-패턴-코드">이전 챕터의 프로미스 패턴 코드</h4>
<ul>
<li>Async/await으로 한 번 더 축약 가능
<img src="https://velog.velcdn.com/images/_upper/post/d22f507b-49e7-477b-98c0-aaa57d657594/image.png" alt=""></li>
</ul>
<h4 id="async-function의-도입">async function의 도입</h4>
<ul>
<li>변수 = await 프로미스인 경우 프로미스가 resolve된 값이 변수에 저장</li>
<li>변수 await 값인 경우 그 값이 변수에 저장
<img src="https://velog.velcdn.com/images/_upper/post/63636763-72d5-4704-b445-880d9ea1b398/image.png" alt=""></li>
</ul>
<h4 id="화살표-함수도-asyncawait-가능">화살표 함수도 async/await 가능</h4>
<p><img src="https://velog.velcdn.com/images/_upper/post/fadc5074-49d7-4ac4-a662-e40934699280/image.png" alt=""></p>
<h4 id="async-함수는-항상-promise를-반환return">Async 함수는 항상 promise를 반환(return)</h4>
<ul>
<li>Then이나 await을 붙일 수 있음
<img src="https://velog.velcdn.com/images/_upper/post/56bcdbdd-ac1e-4411-bd8a-2625eb8604c9/image.png" alt=""></li>
</ul>
<h3 id="for-await-of">for await of</h3>
<h4 id="노드-10부터-지원">노드 10부터 지원</h4>
<h4 id="for-await변수-of-프로미스-배열">for await(변수 of 프로미스 배열)</h4>
<ul>
<li>resolve된 프로미스가 변수에 담겨 나옴</li>
<li>await을 사용하기 때문에 async 함수 안에서 해야함
<img src="https://velog.velcdn.com/images/_upper/post/309e29cc-bff9-4381-a666-8d1fa1642233/image.png" alt=""></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Node.js 섹션2 노드 기본 기능 익히기(1)]]></title>
            <link>https://velog.io/@_upper/Node.js-%EC%84%B9%EC%85%982-%EB%85%B8%EB%93%9C-%EA%B8%B0%EB%B3%B8-%EA%B8%B0%EB%8A%A5-%EC%9D%B5%ED%9E%88%EA%B8%B01</link>
            <guid>https://velog.io/@_upper/Node.js-%EC%84%B9%EC%85%982-%EB%85%B8%EB%93%9C-%EA%B8%B0%EB%B3%B8-%EA%B8%B0%EB%8A%A5-%EC%9D%B5%ED%9E%88%EA%B8%B01</guid>
            <pubDate>Mon, 25 Sep 2023 14:54:28 GMT</pubDate>
            <description><![CDATA[<h2 id="rep과-js-파일-실행하기">REP과 js 파일 실행하기</h2>
<h5 id="repl">REPL</h5>
<p>프롬프트가 &gt; 모양으로 바뀌면, 자바스크립트 코드 입력
입력한 값의 결과값이 바로 출력됨</p>
<h5 id="js-파일을-만들어-실행하기">JS 파일을 만들어 실행하기</h5>
<p>자바스크립트 파일을 만들어 통째로 코드를 실행하는 방법</p>
<ul>
<li>아무 폴더(디렉터리)에서 helloWorld.js를 만들기</li>
<li>node [자바스크립트 파일 경로]로 실행</li>
<li>실행 결과값이 출력굄</li>
</ul>
<hr>
<h2 id="commonjs-모듈-시스템">CommonJS 모듈 시스템</h2>
<h5 id="모듈">모듈</h5>
<p>노드는 자바스크립트 코드를 모듈로 만들 수 있음</p>
<ul>
<li>모듈: 특정한 기능을 하는 함수나 변수들의 집합</li>
<li>모듈로 만들면 여러 프로그램에서 재사용 </li>
</ul>
<h5 id="모듈-만들어보기">모듈 만들어보기</h5>
<p>같은 폴더 내에 var.js, func.js, index.js 만들기</p>
<ul>
<li>파일 끝에 module.exports로 모듈로 만들 값을 지정</li>
<li>다른 파일에서 require(파일 경로)로 그 모듈의 내용 가져올 수 있음</li>
</ul>
<h5 id="파일-간의-모듈-관계">파일 간의 모듈 관계</h5>
<p>node index로 실행</p>
<ul>
<li>const{ odd, even } 부분은 module.exports를 구조분해 할당한 것임
<img src="https://velog.velcdn.com/images/_upper/post/ccfad6ee-eaec-48f5-a0ca-71a106ae4860/image.png" alt=""></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Node.js 섹션0 FAQ & 1강]]></title>
            <link>https://velog.io/@_upper/Node.js-%EC%84%B9%EC%85%980-1%EA%B0%95</link>
            <guid>https://velog.io/@_upper/Node.js-%EC%84%B9%EC%85%980-1%EA%B0%95</guid>
            <pubDate>Sun, 24 Sep 2023 13:10:50 GMT</pubDate>
            <description><![CDATA[<h2 id="노드의-정의">노드의 정의</h2>
<h5 id="nodejs">Node.js</h5>
<p>: 크롬 V8 자바스크립트 엔진으로 빌드된 자바스크립트 런타임</p>
<p>노드는 서버가 아님</p>
<ul>
<li>서버의 역할도 수행할 수 있는 자바스크립트 런타임</li>
<li>노드로 자바스크립트로 작성된 서버를 실행할 수 있음</li>
<li>서버 실행을 위해 필요한 http/https/htpp2 모듈을 제공</li>
</ul>
<p>런타인: 특정언어로 만든 프로그램들을 실행할 수 있게 해주는 가상 머신(크롬의 V8 엔진 사용)의 상태</p>
<hr>
<h2 id="노드의-특성">노드의 특성</h2>
<h5 id="이벤트가-발생할-때-미리-저장해둔-작업을-수행하는-방식">이벤트가 발생할 때 미리 저장해둔 작업을 수행하는 방식</h5>
<p>이벤트의 예: 클릭, 네트워크 요청, 타이머
이벤트 리스너: 이벤트를 등록하는 함수
콜백 함수: 이벤트가 발생했을 때 실행될 함수</p>
<h5 id="논블로킹-io">논블로킹 I/O</h5>
<p>논블로킹: 오래 걸리는 함수를 백그라운드로 보내서 다음 코드가 먼저 실행되게 하고, 나중에 오래 걸리는 함수를 실행</p>
<p>블로킹을 하면 코드가 순서대로 실행되고 논블로킹이면 코드가 순서대로 실행되지 않을 수도 있다</p>
<h5 id="프로세스-vs-스레드">프로세스 vs 스레드</h5>
<p>프로세스: 운영체제에서 할당하는 작업의 단위, 프로세스 간 자원 공유X
스레드: 프로세스 내에서 실행되는 작업의 단위, 부모 프로세스 자원 공유</p>
<h5 id="싱글-스레드">싱글 스레드</h5>
<p>싱글 스레드라 주어진 일을 하나밖에 처리하지 못함</p>
<ul>
<li>프로그래밍 난이도가 쉽고, CPU, 메모리 자원 적게 사용</li>
</ul>
<h5 id="멀티스레드-모델과의-비교">멀티스레드 모델과의 비교</h5>
<p>싱글 스레드 모델을 에러를 처리하지 못하는 경우 멈춤
멀티 스레드 모델은 에러 발생 시 새로운 스레드를 생성하여 극복</p>
<hr>
<h2 id="서버로서의-노드">서버로서의 노드</h2>
<p>서버: 네트워크를 통해 클라이언트에 정보나 서비스를 제공하는 컴퓨터 또는 프로그램</p>
<p>클라이언트: 서버에 요청을 보내는 주체(브라웢, 데스크탑 프로그램, 모바일 앱, 다른 서버에 요청을 보내는 서버)</p>
<p>노드 != 서버 But, 노드는 서버를 구성할 수 있게 하는 모듈을 제공</p>
<h5 id="노드-서버의-장단점">노드 서버의 장단점</h5>
<p>장점:
멀티 스레드 방식에 비해 컴퓨터 자원을 적게 사용함
I/O 작업이 많은 서버로 적합
멀티 스레드 방식보다 쉬움웹 서버가 내장되어 있음
자바스크립트를 사용함
JSON 형식과 호환하기 쉬움</p>
<p>단점:
싱글 스레드라서 CPU 코어를 하나만 사용함
CPU 작업이 많은 서버로는 부적합
하나뿐인 스레드가 멈추지 않도록 관리해야 함
서버 규모가 커졌을 때 서버를 관리하기 어려움
어중간한 성능</p>
<hr>
<h5 id="서버외의-노드">서버외의 노드</h5>
<p>자바스크립트 런타임이기 때문에 용도가 서버에만 한정되지 않음</p>
<p>웹, 모바일, 데스크탑 애플리케이션에도 사용</p>
<ul>
<li>웹 프레잌워크: Angular, React, Vue, Meteor 등</li>
<li>모바일 앱 프레임워크: React Native</li>
<li>데스크탑 개발 도구: Electron(Atom, Slack, VSCode, Discord등 제작)</li>
</ul>
<h2 id="노드-vs-code-설치하기">노드, VS code 설치하기</h2>
<h5 id="노드-설치">노드 설치</h5>
<p><a href="https://nodejs.org/en">https://nodejs.org/en</a>
LTS는 안정적인 버전(3년)</p>
<h5 id="vs-code-설치">vs code 설치</h5>
<p><a href="https://code.visualstudio.com/download">https://code.visualstudio.com/download</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JS 챌린지 5일차 TIL]]></title>
            <link>https://velog.io/@_upper/JS-%EC%B1%8C%EB%A6%B0%EC%A7%80-5%EC%9D%BC%EC%B0%A8-TIL</link>
            <guid>https://velog.io/@_upper/JS-%EC%B1%8C%EB%A6%B0%EC%A7%80-5%EC%9D%BC%EC%B0%A8-TIL</guid>
            <pubDate>Mon, 11 Sep 2023 14:59:15 GMT</pubDate>
            <description><![CDATA[<h2 id="while문">while문</h2>
<p>while: 조건식이 만족하면 중괄호에 둘러싸인 코드를 반복 실행한다.</p>
<pre><code class="language-javascript">while( /*조건식*/ ){
    /* 반복 실행될 코드 */
}</code></pre>
<h2 id="do-while문">do while문</h2>
<p>do while:반복을 할질 말지 반복문 마지막에 검사한다. 즉 반복문 한번은 실행하고 더 반복을 할지 말지는 코드를 보고 결정</p>
<pre><code class="language-javascript">do{
    /* 반복 실행될 코드 */
}while( /*조건식*/ );</code></pre>
<h2 id="for문">for문</h2>
<p>for: 특정 횟수만큼 반복하거나 배열과 같은 데이터 구조의 요소를 반복적으로 처리할 수 있다</p>
<pre><code class="language-javascript">var sum = 0;
for( var i = 0 ; i &lt; 5 ; i++ ){
    sum = sum + i;
}</code></pre>
<h2 id="for-in문">for in문</h2>
<p>for in: 객체의 열거 가능한 속성을 반복적으로 순회하고 처리하는 데 사용되는 반복문
객체 내의 모든 속성을 열거하고 값을 출력하는 반복문</p>
<h5 id="for">for</h5>
<pre><code class="language-javascript">var property_list = Object.keys(obj);

for( var i=0 ; i&lt;property_list.length ; i++ ){
    var propertyName = property_list[i];
    console.log( &quot;\t&quot;, propertyName, &quot;: &quot;, obj[propertyName] );
}</code></pre>
<h5 id="for-in">for in</h5>
<pre><code class="language-javascript">for( var propertyName in obj ){
    console.log( &quot;\t&quot;, propertyName, &quot;: &quot;, obj[propertyName] );
}</code></pre>
<h2 id="변수의-scope">변수의 scope</h2>
<p>scope: 변수와 함수가 접근 가능한 범위를 나타내는 개념</p>
<p>변수의 scope는 function의 scope를 따른다
-&gt; 객체(변수)는 선언된 함수 안에서만 접근이 가능하다</p>
<h2 id="변수의-shadowing">변수의 shadowing</h2>
<p>shadowing: 동일한 이름의 변수나 함수가 여러 스코프에서 사용되는 경우 바깥 스코프의 변수나 함수를 가려버리는 현상</p>
<pre><code class="language-javascript">function name
    //한 함수 안에서만 값이 유지되는 변수
    var in_function_var;
}

    //여러 함수에서 값이 유지되면서 사용되는 변수
    var out_function_var;</code></pre>
<h2 id="method-this">method, this</h2>
<p>method: 객체 속성의 값으로써 함수가 들어갈 때</p>
<p>this: 함수가 불렸을 때 어떤 객체 바인드된 속성으로써 불렸는지 알려준다</p>
<p>일반적임 함수를 호출할 때, 해당 함수 내부에서 사용된 this는 전역객체(브라우저의 경우 window객체)에 바인딩 된다.</p>
<p><img src="https://velog.velcdn.com/images/_upper/post/606ec380-8006-42e2-8d81-d62a40fc1552/image.png" alt=""></p>
<p>메서드를 호출할 때 this의 값은 인스턴스화 된 객체(해당 메서드를 호출한 객체)를 참조한다.</p>
<h2 id="closure-클로저">closure (클로저)</h2>
<p>함수와 함수가 선언될 때 environment로 구성</p>
<pre><code class="language-javascript">function makeCounterFunction(initVal){
    var count = initVal;
    function Increase(){
        count++;
        console.log(count);
    }
    return Increase;
}

var counter1 = makeCounterFunction(0);
var counter2 = makeCounterFunction(10);
</code></pre>
<p><img src="https://velog.velcdn.com/images/_upper/post/07119b54-1a4b-4932-ba12-075aa42ad307/image.png" alt=""></p>
<hr>
<p><img src="https://velog.velcdn.com/images/_upper/post/3bad23a5-f52f-4115-a354-e43821f8a91f/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JS 챌린지 4일차 TIL]]></title>
            <link>https://velog.io/@_upper/JS-%EC%B1%8C%EB%A6%B0%EC%A7%80-4%EC%9D%BC%EC%B0%A8-TIL</link>
            <guid>https://velog.io/@_upper/JS-%EC%B1%8C%EB%A6%B0%EC%A7%80-4%EC%9D%BC%EC%B0%A8-TIL</guid>
            <pubDate>Sun, 10 Sep 2023 14:57:06 GMT</pubDate>
            <description><![CDATA[<h2 id="배열-만들기">배열 만들기</h2>
<p>배열: 값 즉 element가 연속된 저장 공간
여러개의 값을 저장하고 인덱스를 이용해 접근할 수 있다.</p>
<p>빈배열
초기화된 배열
element에는 어떤 자료형이든 저장될 수 있다
<img src="https://velog.velcdn.com/images/_upper/post/20cd4cdf-c9f6-4aba-8056-e00288366318/image.png" alt=""></p>
<p>배열의 길이는 .length를 사용</p>
<p>대괄호 안에 인덱스를 사용해서 배열의 element 접근
arr[index]</p>
<h2 id="배열-사용하기">배열 사용하기</h2>
<p>push(): 배열의 끝에 하나 이상의 요소를 추가, 배열의 길이를 반환</p>
<p>pop(): 배열의 마지막 요소를 제거하고 반환</p>
<p>shift(): 배열의 첫 번째 요소를 제거하고 반환</p>
<p>unshift(): 배열의 맨 앞에 하나 이상의 요소를 추가</p>
<p>reverse(): 배열의 순서를 거꾸로 뒤집기</p>
<p>sort(): 배열의 요소를 기본적으로 문자열로 변환한 후 유니코드 코드 포인트 값 순서로 정렬</p>
<p>arr1.concat(arr2) : arr1과 arr2 붙임</p>
<p>arr.indexOf(element) : arr에서 element가 있는 첫 위치를 검색</p>
<p>arr.lastIndexOf(element) : arr에서 element가 있는 마지막 위치를 검색</p>
<p>split(): 문자열을 특정 구분자를 기준으로 나누어 배열로 반환</p>
<h2 id="주석">주석</h2>
<p>주석: 프로그래밍 코드 내에 설명을 추가하거나 임시로 코드를 비활성화하기 위해 사용되는 텍스트</p>
<p>한 줄 주석: //를 사용하여 한 줄 주석을 작성</p>
<p>여러 줄 주석: /*로 시작하여 */로 끝나는 여러 줄 주석을 작성할 수 있다</p>
<h2 id="if문">if문</h2>
<p>if: 주어진 조건이 true인 경우 특정 코드 블록을 실행하고 조건이 false인 경우 다른 코드 블록이 실행되도록 프로그램의 흐름을 제어한다</p>
<p><img src="https://velog.velcdn.com/images/_upper/post/30a27403-471d-45e6-88de-cd180dc49b73/image.png" alt=""></p>
<h2 id="switch문">switch문</h2>
<p>switch: 특정 변수나 표현식의 값을 검사하고 그 값에 따라 여러 다른 코드 블록 중 하나를 실행</p>
<p>break: case 블록 내에서 코드를 실행한 후 break 문을 사용하여 switch 문을 빠져나온다. 
break를 사용하지 않으면 해당 case 이후의 모든 코드가 실행된다</p>
<p>default: 어떤 case 절에도 해당하지 않을 때 실행할 코드를 정의</p>
<p><img src="https://velog.velcdn.com/images/_upper/post/d5696b27-1ca0-4c2a-a038-492093f41a83/image.png" alt=""></p>
<hr>
<p><img src="https://velog.velcdn.com/images/_upper/post/c72b0af5-bb98-4ed2-ab3d-8e25c4483e6a/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JS 챌린지 3일차 TIL]]></title>
            <link>https://velog.io/@_upper/JS-%EC%B1%8C%EB%A6%B0%EC%A7%80-3%EC%9D%BC%EC%B0%A8-TIL</link>
            <guid>https://velog.io/@_upper/JS-%EC%B1%8C%EB%A6%B0%EC%A7%80-3%EC%9D%BC%EC%B0%A8-TIL</guid>
            <pubDate>Sun, 10 Sep 2023 14:02:36 GMT</pubDate>
            <description><![CDATA[<h2 id="산술연산자">산술연산자</h2>
<p>Arithmetic(산술), Operator(연상자)
a+b
a-b</p>
<p><img src="https://velog.velcdn.com/images/_upper/post/9cd40f12-e9e7-4cb6-9e5b-10fbbbc60e56/image.png" alt=""></p>
<p>++: 변수의 값을 증가시키는 연산자
--: 변수의 값을 감소시키는 연산자</p>
<pre><code class="language-javascript">var a = 5;
var result1 = a++; // 후위 증가 연산자 사용
console.log(result1); // 출력: 5
console.log(a); // 출력: 6

var b = 5;
let result2 = ++b; // 전위 증가 연산자 사용
console.log(result2); // 출력: 6
console.log(b); // 출력: 6
</code></pre>
<pre><code class="language-javascript">Math.pow(A,b); // A의 B승
Math.sqrt(A); // A의 제곱근
MAth.random(); // 0~1 사이의 임의의 난수를 발생</code></pre>
<h2 id="함수-사용하기">함수 사용하기</h2>
<p>함수를 &#39;호출&#39; 한다</p>
<pre><code class="language-javascript">console.log(&quot;콘솔에 로그를 남기는 함수&quot;);</code></pre>
<h5 id="함수-선언">함수 선언</h5>
<pre><code class="language-javascript">function 함수이름(파라미터1, 파라미터2){
    /*
        실행될 코드
    */
    return 반환값;
}</code></pre>
<h2 id="관계연산자">관계연산자</h2>
<p>Relational(관계), Operator(연산자)</p>
<p><img src="https://velog.velcdn.com/images/_upper/post/42f9be0f-2730-4c5d-a781-b457234af238/image.png" alt=""></p>
<h5 id="논리연산자">논리연산자</h5>
<p>Logical(논리), Operator(연산자)</p>
<p>AND(&amp;&amp;): 두 피연산자가 모두 true인 경우에만 true를 나타내는 이항연산자</p>
<p>OR(||): 두 피연산자가 하나라도 true인 경우 true를 나타내는 이항연산자</p>
<p>NOT(!): 피연산자가 true인 경우 false를, false인 경우 true를 나타내는 단항연산자</p>
<h2 id="연산자-우선순위">연산자 우선순위</h2>
<p><img src="https://velog.velcdn.com/images/_upper/post/fba24f27-bceb-48aa-8c46-7bae67a68855/image.png" alt=""></p>
<h2 id="string-이어붙이기">String 이어붙이기</h2>
<p>.length: 문자열 내 문자의 개수를 나타낸다</p>
<p>.concat: 현재 문자열과 다른 문자열을 결합하여 새로운 문자열을 생성한다</p>
<p>+(str + str) : 더하기 연산자를 사용하여 문자열을 연결할 수 있다</p>
<h2 id="string-다루기">String 다루기</h2>
<h5 id="특정-위치의-문자열-알아내기">특정 위치의 문자열 알아내기</h5>
<ol>
<li><p>문자열에서 지정한 인덱스 위치에 있는 문자를 반환한다 (0부터 시작)</p>
</li>
<li><p>대괄호 []를 사용하여 문자열에서 특정 인덱스 위치에 있는 문자를 가져올 수 있다 (0부터 시작)</p>
</li>
</ol>
<h5 id="부분문자열-구하기">부분문자열 구하기</h5>
<p>substring(): 문자열 내에서 지정된 시작 인덱스와 종료 인덱스 사이의 문자열 부분을 추출</p>
<p>substr(): 문자열 내에서 지정된 시작 인덱스부터 지정된 길이 만큼의 문자열 부분을 추출</p>
<h5 id="문자열-탐색하기">문자열 탐색하기</h5>
<p>indexOf(str): 문자열에서 특정 문자열 str이 처음으로 나타나는 위치의 인덱스를 반환
*str을 찾을 수 없으면 -1을 반환</p>
<p>lastIndexOf(str) :메서드는 문자열에서 특정 문자열 str이 마지막으로 나타나는 위치의 인덱스를 반환
*str을 찾을 수 없으면 -1을 반환</p>
<hr>
<p><img src="https://velog.velcdn.com/images/_upper/post/a49429ea-d529-4a8e-9464-dd51210adf74/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JS 챌린지 2일차 TIL]]></title>
            <link>https://velog.io/@_upper/JS-%EC%B1%8C%EB%A6%B0%EC%A7%80-2%EC%9D%BC%EC%B0%A8-TIL</link>
            <guid>https://velog.io/@_upper/JS-%EC%B1%8C%EB%A6%B0%EC%A7%80-2%EC%9D%BC%EC%B0%A8-TIL</guid>
            <pubDate>Sat, 09 Sep 2023 14:53:40 GMT</pubDate>
            <description><![CDATA[<h2 id="number">Number</h2>
<h5 id="lecture05js">lecture05.js</h5>
<pre><code class="language-javascript"> var height=prompt(&quot;키를 입력해 주세요&quot;);
 console.log(height, typeof(height));</code></pre>
<pre><code class="language-javascript"> var height_int = pareInt(height);
 console.log(height_int, typeof(height_int));

 var height_float = parseFloat(height);
 console.log(height_float, typeof(height_float));</code></pre>
<p>parseInt: 문자열을 정수로 변환
parseFloat: 문자열을 실수로 변환</p>
<h2 id="string">String</h2>
<p>string: 텍스트 데이터를 나타내는 데이터 타입
&quot;쌍따옴표&quot;와 &#39;따옴표&#39; 모두 문자열 표현 가능</p>
<p>Escape Character: 쌍따옴표나 따옴표를 작성하려면 앞뒤로 &#39;&#39; 사용
역슬래시를 사용하려면 알뒤로 &#39;\&#39; 사용</p>
<p><img src="https://velog.velcdn.com/images/_upper/post/6046da3b-9c87-4dfd-b213-f033c6f3f46f/image.png" alt=""></p>
<p>syntaxError: 잘못된 문법이라서 발생하는 에러</p>
<h2 id="object">Object</h2>
<p>object: 다양한 데이터 유형을 포함할 수 있는 복합 데이터 타입</p>
<p>객체 생성: 객체는 중괄호 {}를 사용하여 생성, 속성을 콜론(:)으로 연결하여 정의</p>
<p>속성: 객체는 이름(키)과 해당 값을 가지는 속성의 집합으로 구성</p>
<p>속성 접근: 객체의 속성에 접근할 때는 점(.) 표기법 또는 대괄호([]) 표기법을 사용</p>
<p><img src="https://velog.velcdn.com/images/_upper/post/b84d86cf-7f63-4d3d-aa7b-96a3b0f28c9e/image.png" alt=""></p>
<h2 id="undefined와-null">undefined와 null</h2>
<p>아무것도 저장되어 있지 않는 무의 상태</p>
<p>undefined: 변수나 속성이 선언되었지만 아무런 값도 할당되지 않았을 때 나타나는 값</p>
<p>null: 명시적으로 값이 없음을 나타내는 비어있는 상태</p>
<p><img src="https://velog.velcdn.com/images/_upper/post/bd425bdf-a643-4d97-9b7c-5abfad3a54c3/image.png" alt=""></p>
<hr>
<p><img src="https://velog.velcdn.com/images/_upper/post/e8beef6c-f6a0-4450-a3e1-ca49ec0cde2c/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JS 챌린지 1일차 TIL]]></title>
            <link>https://velog.io/@_upper/JS-%EC%B1%8C%EB%A6%B0%EC%A7%80-1%EC%9D%BC%EC%B0%A8-TIL</link>
            <guid>https://velog.io/@_upper/JS-%EC%B1%8C%EB%A6%B0%EC%A7%80-1%EC%9D%BC%EC%B0%A8-TIL</guid>
            <pubDate>Sat, 09 Sep 2023 14:06:58 GMT</pubDate>
            <description><![CDATA[<h2 id="실습환경-만들기">실습환경 만들기</h2>
<p>서브라임 텍스트 에디터
<a href="http://www.sublimetext.com">www.sublimetext.com</a></p>
<h5 id="indexhtml">index.html</h5>
<pre><code class="language-HTML">&lt;html&gt;
    &lt;head&gt;
        &lt;meata charset=&quot;utf-8&quot;&gt;
    &lt;/head&gt;
    &lt;body&gt;
        This is a basic HTML page
    &lt;/body&gt;
&lt;/html&gt;</code></pre>
<h5 id="lecture01js">lecture01.js</h5>
<pre><code class="language-javascript">alert(&quot;Hello Javascript&quot;);</code></pre>
<p>브라우저에 경고메시지 출력</p>
<h2 id="developer-console-사용하기">Developer Console 사용하기</h2>
<p>console.log: 메세지를 출력하는 함수</p>
<h5 id="lecture02js">lecture02.js</h5>
<pre><code class="language-javascript">console.log(&quot;Hello developer console&quot;);
console.log(&quot;2&quot;);
console.log(&quot;3&quot;);</code></pre>
<p>프로그램의 실행 순서는 순차적으로 실행된다.
콘솔에서 명령어를 직접 실행할 수 있다.
<img src="https://velog.velcdn.com/images/_upper/post/fb20f34d-ff08-4d87-b938-d5babc38ac83/image.png" alt=""></p>
<h2 id="변수-선언과-초기화">변수 선언과 초기화</h2>
<p>변수: 정보를 저장해 주는 곳
초기화: 변수를 선언하고 처음으로 변수의 값을 저장하는 작업
변수 저장: ex) a=10;</p>
<h2 id="변수의-활용">변수의 활용</h2>
<p>prompt: 사용자가 입력한 것을 저장</p>
<pre><code class="language-javascript">var name = prompt(&quot;이름을 입력해 주세요.&quot;);
console.log(name, &quot;님 환영합니다.&quot;);</code></pre>
<h2 id="기본-자료형">기본 자료형</h2>
<p>자료형: 변수에 저장할 수 있는 값의 종류(Type)
<img src="https://velog.velcdn.com/images/_upper/post/8681e649-3407-4d2f-b0f6-35928d8eeb60/image.png" alt=""></p>
<p>typeof: 괄호 뒤의 변수가 어떤 자료형인지 알려주는 명령
<img src="https://velog.velcdn.com/images/_upper/post/6f810dbd-0d3b-47cd-bb98-5340c8d1ebe3/image.png" alt=""></p>
<hr>
<p><img src="https://velog.velcdn.com/images/_upper/post/8893c3eb-4355-4212-beae-13a1128ecf34/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[WYSIWYG의 소개 및 적용 (작정하고 장고 44강)]]></title>
            <link>https://velog.io/@_upper/WYSIWYG%EC%9D%98-%EC%86%8C%EA%B0%9C-%EB%B0%8F-%EC%A0%81%EC%9A%A9-%EC%9E%91%EC%A0%95%ED%95%98%EA%B3%A0-%EC%9E%A5%EA%B3%A0-44%EA%B0%95</link>
            <guid>https://velog.io/@_upper/WYSIWYG%EC%9D%98-%EC%86%8C%EA%B0%9C-%EB%B0%8F-%EC%A0%81%EC%9A%A9-%EC%9E%91%EC%A0%95%ED%95%98%EA%B3%A0-%EC%9E%A5%EA%B3%A0-44%EA%B0%95</guid>
            <pubDate>Fri, 07 Jul 2023 12:49:36 GMT</pubDate>
            <description><![CDATA[<h2 id="44강">44강</h2>
<ul>
<li>Medium Editor 를 사용하여 WYSIWYG를 통해 게시글 작성할 수 있도록 만들어보기</li>
</ul>
<h4 id="wysiwyg">WYSIWYG</h4>
<p>게시판 기능 중 하나
<img src="https://velog.velcdn.com/images/_upper/post/a6d690a3-7104-4af4-933f-1b972d622d87/image.png" alt=""></p>
<p>텍스트를 좀 더 굵게하거나 크게하거나 글을 쓸 때 좀 더 풍부하게 해주기</p>
<p>Medium Editor github:  <a href="https://github.com/yabwe/medium-editor">https://github.com/yabwe/medium-editor</a> </p>
<p>Demo : <a href="https://yabwe.github.io/medium-editor/">https://yabwe.github.io/medium-editor/</a></p>
<p>articleapp/forms.py</p>
<pre><code>class ArticleCreationForm(ModelForm):
    content = forms.CharField(widget=forms.Textarea(attrs={&#39;class&#39;: &#39;editable&#39;}))

    class Meta:
        model = Article
        fields = [&#39;title&#39;, &#39;image&#39;, &#39;project&#39;, &#39;content&#39;]</code></pre><p>For the latest version:</p>
<pre><code>&lt;script src=&quot;//cdn.jsdelivr.net/npm/medium-editor@latest/dist/js/medium-editor.min.js&quot;&gt;&lt;/script&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;//cdn.jsdelivr.net/npm/medium-editor@latest/dist/css/medium-editor.min.css&quot; type=&quot;text/css&quot; media=&quot;screen&quot; charset=&quot;utf-8&quot;&gt;</code></pre><p> instantiate a new MediumEditor object:</p>
<pre><code>&lt;script&gt;var editor = new MediumEditor(&#39;.editable&#39;);&lt;/script&gt;</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Field Lookup을 사용한 구독 페이지 구현 (작정하고 장고 43강)]]></title>
            <link>https://velog.io/@_upper/Field-Lookup%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%9C-%EA%B5%AC%EB%8F%85-%ED%8E%98%EC%9D%B4%EC%A7%80-%EA%B5%AC%ED%98%84-%EC%9E%91%EC%A0%95%ED%95%98%EA%B3%A0-%EC%9E%A5%EA%B3%A0-43%EA%B0%95</link>
            <guid>https://velog.io/@_upper/Field-Lookup%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%9C-%EA%B5%AC%EB%8F%85-%ED%8E%98%EC%9D%B4%EC%A7%80-%EA%B5%AC%ED%98%84-%EC%9E%91%EC%A0%95%ED%95%98%EA%B3%A0-%EC%9E%A5%EA%B3%A0-43%EA%B0%95</guid>
            <pubDate>Fri, 07 Jul 2023 12:34:08 GMT</pubDate>
            <description><![CDATA[<h2 id="43강">43강</h2>
<ul>
<li>장고에서 제공하는 DB Query를 위한 기능, Field Lookup을 사용하여 사용자가 구독한 게시판의 게시글만 볼 수 있는 구독페이지를 만들어보기 </li>
</ul>
<h4 id="filter">filter</h4>
<p><img src="https://velog.velcdn.com/images/_upper/post/a2c050d4-f0f5-4554-8fdf-f8869989d150/image.png" alt=""></p>
<p>들어가는 조건들은 AND function이다</p>
<p>OR와 WHERE func을 사용하기 위해서는</p>
<ol>
<li>Find user Subscripted projects</li>
<li>Find articles in projects</li>
</ol>
<p><img src="https://velog.velcdn.com/images/_upper/post/4745515f-3ed4-43ae-9e0f-7182bbc4da6d/image.png" alt=""></p>
<p>SQL문은 위 처럼 사용</p>
<p><img src="https://velog.velcdn.com/images/_upper/post/cb66488d-cb77-40da-85be-ace29ec9af5c/image.png" alt=""></p>
<p>여러가지 Field LookUps이 있음</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[RedirectView를 통한 SubscribeApp 시작 (작정하고 장고 42강)]]></title>
            <link>https://velog.io/@_upper/RedirectView%EB%A5%BC-%ED%86%B5%ED%95%9C-SubscribeApp-%EC%8B%9C%EC%9E%91-%EC%9E%91%EC%A0%95%ED%95%98%EA%B3%A0-%EC%9E%A5%EA%B3%A0-42%EA%B0%95</link>
            <guid>https://velog.io/@_upper/RedirectView%EB%A5%BC-%ED%86%B5%ED%95%9C-SubscribeApp-%EC%8B%9C%EC%9E%91-%EC%9E%91%EC%A0%95%ED%95%98%EA%B3%A0-%EC%9E%A5%EA%B3%A0-42%EA%B0%95</guid>
            <pubDate>Fri, 07 Jul 2023 12:23:09 GMT</pubDate>
            <description><![CDATA[<h2 id="42강">42강</h2>
<ul>
<li>RedirectView 기반의 구독 시스템, 즉 SubscribeApp을 만들기</li>
</ul>
<p>RedirectView 사용하는 이유</p>
<p>구독버튼을 누를 때 따로 입력창이 중간에 없어도 요청받자마자 처리할 수 있게 하기 위해</p>
<p>projectapp/views.py</p>
<pre><code>    def get_context_data(selfself, **kwargs):
        project = self.object
        user = self.request.user

        if user.is_authenticated:
            subscription = Subscription.objects.filter(user=user, project=project)
        object_list = Article.objects.filter(project=self.get_object())
        return super(ProjectDetailView, self).get_context_data(object_list=object_list,
                                                               subscription=subscription
                                                                **kwargs)</code></pre><p>template에서 subscription을 통해서 구독 정보가 있는지 없는지 확인할 수 있음</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[MultipleObjectMixin을 통한  ProjectApp 마무리 (작정하고 장고 41강)
]]></title>
            <link>https://velog.io/@_upper/MultipleObjectMixin%EC%9D%84-%ED%86%B5%ED%95%9C-ProjectApp-%EB%A7%88%EB%AC%B4%EB%A6%AC-%EC%9E%91%EC%A0%95%ED%95%98%EA%B3%A0-%EC%9E%A5%EA%B3%A0-41%EA%B0%95</link>
            <guid>https://velog.io/@_upper/MultipleObjectMixin%EC%9D%84-%ED%86%B5%ED%95%9C-ProjectApp-%EB%A7%88%EB%AC%B4%EB%A6%AC-%EC%9E%91%EC%A0%95%ED%95%98%EA%B3%A0-%EC%9E%A5%EA%B3%A0-41%EA%B0%95</guid>
            <pubDate>Fri, 07 Jul 2023 11:44:01 GMT</pubDate>
            <description><![CDATA[<h2 id="41강">41강</h2>
<ul>
<li>Project와 Article을 연결하는 작업, 그리고 MultipleObjectMixin 을 이용해서 ProjectApp 의 Detail 페이지를 마무리 하고, 같은 방식으로 AccountApp 의 디테일 페이지도 수정한다</li>
</ul>
<p><img src="https://velog.velcdn.com/images/_upper/post/57399ff5-116e-4179-a27d-af5fc4e7e4b3/image.png" alt=""></p>
<p>댓글을 만들면선 for문을 돌 때 target_article에 foreignkey로 연결되어 있는 comment를 all로 불러와서 for문으로 돌리기</p>
<p>하지만 무조건 다 가져오는 것 문제고 복잡도를 높이는 것도 문제
여러가지 작업을 하고 싶을 땐 한계가 있음</p>
<h4 id="해결을-위해-in-view-using-mixin를-사용">해결을 위해 In View Using Mixin를 사용</h4>
<p>여러가지 오브젝트를 다룰 수 있게 만들어주는 mixin이다</p>
<p>projectapp/views.py</p>
<pre><code>class ProfileDetailView(DetailView, MultipleObjectMixin):
    model = Project
    context_object_name = &#39;target_project&#39;
    template_name = &#39;projectapp/detail.html&#39;

    paginate_by = 25

    def get_context_data(selfself, **kwargs):
        object_list = Article.objects.filter(project=self.get_object())
        return super(ProjectDetailView, self).get_context_data(object_list=object_list, **kwargs)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[ProjectApp 구현 (작정하고 장고 40강)]]></title>
            <link>https://velog.io/@_upper/ProjectApp-%EA%B5%AC%ED%98%84-%EC%9E%91%EC%A0%95%ED%95%98%EA%B3%A0-%EC%9E%A5%EA%B3%A0-40%EA%B0%95</link>
            <guid>https://velog.io/@_upper/ProjectApp-%EA%B5%AC%ED%98%84-%EC%9E%91%EC%A0%95%ED%95%98%EA%B3%A0-%EC%9E%A5%EA%B3%A0-40%EA%B0%95</guid>
            <pubDate>Thu, 06 Jul 2023 20:57:14 GMT</pubDate>
            <description><![CDATA[<h2 id="40강">40강</h2>
<ul>
<li>게시판에 해당하는 projectapp을 구현
<img src="https://velog.velcdn.com/images/_upper/post/93a2d062-517b-4a85-af7c-50f16e2298d8/image.png" alt=""></li>
</ul>
<p><img src="https://velog.velcdn.com/images/_upper/post/31727b76-f51e-4818-ad90-138680048489/image.png" alt=""></p>
<p>projectapp 만들고 update와 delete는 따로 admin이 가능하도록 설정하고 따로 하진 않을 것임</p>
<pre><code>a:hover {
  color: black;  
}</code></pre><p>어떤 요소에 마우스를 올렸을 때 어떤 행동을 할 건지를 설정해주는 값</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[모바일 디버깅, 반응형 레이아웃 (작정하고 장고 39강)]]></title>
            <link>https://velog.io/@_upper/%EB%AA%A8%EB%B0%94%EC%9D%BC-%EB%94%94%EB%B2%84%EA%B9%85-%EB%B0%98%EC%9D%91%ED%98%95-%EB%A0%88%EC%9D%B4%EC%95%84%EC%9B%83-%EC%9E%91%EC%A0%95%ED%95%98%EA%B3%A0-%EC%9E%A5%EA%B3%A0-39%EA%B0%95</link>
            <guid>https://velog.io/@_upper/%EB%AA%A8%EB%B0%94%EC%9D%BC-%EB%94%94%EB%B2%84%EA%B9%85-%EB%B0%98%EC%9D%91%ED%98%95-%EB%A0%88%EC%9D%B4%EC%95%84%EC%9B%83-%EC%9E%91%EC%A0%95%ED%95%98%EA%B3%A0-%EC%9E%A5%EA%B3%A0-39%EA%B0%95</guid>
            <pubDate>Thu, 06 Jul 2023 20:16:42 GMT</pubDate>
            <description><![CDATA[<h2 id="39강">39강</h2>
<ul>
<li>모바일 기기로 직접 우리가 만든 사이트를 접속하여 모바일에서 실제로 보여지는 화면이 어떤지 확인해보고, 반응형 레이아웃을 위한 설정을 다루기.</li>
</ul>
<p>모바일 앱으로 접속
python manage.py runserver = 127.0.0.1:8000</p>
<pre><code> python manage.py runserver 0.0.0.0:8080</code></pre><p>templates/head.html</p>
<pre><code>&lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1, shrink-to-fit=no&quot;&gt;</code></pre><p>모바일 디바이스 설정</p>
<p>static/base.css</p>
<pre><code>@media screen and (max-width:500px) {
    html{
        font-size: 13px;
    }
}</code></pre><p>screen 사이즈가 500이하로 떨어지면 html 안에 있는 font-size를 16px 13px로 작아짐</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Commentapp 마무리 (작정하고 장고 38강)]]></title>
            <link>https://velog.io/@_upper/Commentapp-%EB%A7%88%EB%AC%B4%EB%A6%AC-%EC%9E%91%EC%A0%95%ED%95%98%EA%B3%A0-%EC%9E%A5%EA%B3%A0-38%EA%B0%95</link>
            <guid>https://velog.io/@_upper/Commentapp-%EB%A7%88%EB%AC%B4%EB%A6%AC-%EC%9E%91%EC%A0%95%ED%95%98%EA%B3%A0-%EC%9E%A5%EA%B3%A0-38%EA%B0%95</guid>
            <pubDate>Thu, 06 Jul 2023 19:33:31 GMT</pubDate>
            <description><![CDATA[<h2 id="38강">38강</h2>
<ul>
<li>View 파트를 수정하지 않고 template 내에서 for 문을 통해 댓글을 시각화 하는 작업 및 CommentApp 나머지 부분을 마무리한다.</li>
</ul>
<p>commetapp/migrations/views.py</p>
<pre><code>class CommentCreateView(CreateView):
    model = Comment
    form_class = CommentCreationForm
    template_name = &#39;commentapp/create.html&#39;


    def form_valid(self, form):

        temp_comment = form.save(commit=False)
        temp_comment.article = Article.objects.get(pk=self.request.POST[&#39;article_pk&#39;])
        temp_comment.writter = self.request.user
        temp_comment.save()
        return super().form_valid(form)

    def get_success_url(self):
        return reverse(&#39;articleapp:detail&#39;, kwargs={&#39;pk&#39;: self.object.article.pk})



@method_decorator(comment_ownership_required, &#39;get&#39;)
@method_decorator(comment_ownership_required, &#39;post&#39;)

class CommentDeleteView(DeleteView):
    model = Comment
    context_object_name = &#39;target_comment&#39;
    template_name = &#39;commentapp/delete.html&#39;

    def get_success_url(self):
        return reverse(&#39;articleapp:detail&#39;, kwargs={&#39;pk&#39;: self.object.article.pk})</code></pre><p>commentapp/templates/detail.thml</p>
<pre><code>&lt;div style=&quot;border: 1px solid; text-align: left; padding: 4%; margin: 1rem 0; bogrder-radius: 1rem;
            border-color: #bbb;&quot;&gt;
    &lt;div&gt;
        &lt;strong&gt;
            {{ comment.writer.profile.nickname }}
        &lt;/strong&gt;
        &amp;nbsp&amp;nbsp&amp;nbsp
        {{ comment.created_at }}
    &lt;/div&gt;
    &lt;div style=&quot;margin: 1rem 0;&quot;&gt;
        {{ comment.content }}
    &lt;/div&gt;
    {% if comment.writter == user %}
    &lt;div style=&quot;text-align: right&quot;&gt;
        &lt;a href=&quot;{% url &#39;commentapp:delete&#39; pk=comment.pk %}&quot;\\
            class=&quot;btn btn-danger rounded-pill&quot;&gt;
            Delete
        &lt;/a&gt;

    &lt;/div&gt;
    {% endif %}</code></pre>]]></description>
        </item>
    </channel>
</rss>