일반적으로 웹사이트는 여러개의 자바스크립트로 이루어져 있음
자바스크립트는 파일들을 각각 별개의 프로그램으로 취급
예전 자바스크립트 파일들은 전역 스코프에 존재하는 변수/함수를 사용해야 했음
즉시 실행함수 등을 통해 전역 스코프가 오염되는 것을 막을수는 있었지만, 스크립트 파일간 의존도를 확인하기 힘들고 실행순서를 제어해야한다는 한계점 존재!
모듈 : 설계 시점에 의미있는 요소 (우리가 의식적으로 나눠놓은 요소)
컴포넌트 : 런타임 시점에 의미있는 요소 (나눠놓은 요소에 포함되어 실행되는 요소)
모듈
모듈의 특징
Webpack 등을 이용하여 번들링한 스크립트를 불러오면 크게 type="module"을 사용할 일이 별로 없음
기본 개념 - CSS (Coded Character Set)
기본 개념 - CES (Character Encoding Scheme)
기본 개념 - TES(Transfer Encoding Syntax)
유니코드

유니코드 - CSS


유니코드 - CES



정규표현식


정규표현식 표현

Ex) 휴대폰 번호를 찾아보자.

Q : 휴대폰 번호의 패턴은?
A : 세자리 숫자, 하이픈, 셋 혹은 네 자리 숫자, 하이픈, 네 자리 숫자 패턴으로 이루어짐
-> \d{3}-\d{3,4}-\d{4}

Ex) 이메일의 주소를 찾아보자.

Q : 이메일의 패턴은?
A : 문자열, @, 문자열, ., 문자열 패턴으로 이루어짐
-> .+@.+..+

Q : 여기서 naver, grepp과 같은 중간 문자열만 뽑고 싶다면?
A : 캡처 (...)를 이용하면 원하는 부분만 뽑아낼 수 있음 (여러번 사용 가능)
-> .+@(.+)..+

JavaScript에서의 정규표현식
생성 방법
// 생성자 함수 방식
// new RegExp(표현식)
const regExp1 = new RegExp("^\d+");
// new RegExp(표현식, 플래그)
const regExp2 = new RegExp("^\d+", "gi");
// 리터럴 방식
// /표현식/
const regexp1 = /^\d+/;
// /표현식/플래그
> const regexp2 = /^\d+/gi;
test
const message = "안녕하세요. 010-1234-5678로 연락주세요.";
const message2 = "안녕하세요. 연락하지 마세요.";
// 정규표현식 리터럴
const regExp = /\d{3}-\d{3,4}-\d{4}/;
console.log(regExp.test(message)); // true
console.log(regExp.test(message2)); // flase
exec
const message = "안녕하세요. 010-1234-5678로 연락주세요.";
const message2 = "안녕하세요. 연락하지 마세요.";
// 정규표현식 리터럴
const regExp = /\d{3}-\d{3,4}-\d{4}/;
console.log(regExp.exec(message));
console.log(regExp.exec(message2));

match
const message = "안녕하세요. 010-1234-5678로 연락주세요.";
const message2 = "안녕하세요. 010-1234-5678말고, 010-9876-5432로 연락주세요.";
// 정규표현식 리터럴
const regExp = /\d{3}-\d{3,4}-\d{4}/;
// 무조건 처음 매칭된 것을 반환
console.log(message.match(regExp));
console.log(message2.match(regExp));
//모두 탐색하려면 matchAll을 사용해야 함
console.log([...message2.matchAll(/\d{3}-\d{3,4}-\d{4}/g)]);

replace
const message = "안녕하세요. 010-1234-5678로 연락주세요.";
const message2 = `안녕하세요. 010-1234-5678말고, 010-9876-5432로 연락주세요.`
// 정규표현식 리터럴
const regExp = /\d{3}-\d{3,4}-\d{4}/;
console.log(message.replace(regExp, "전화번호"));
console.log(message2.replace(regExp, "전화번호"));
// 옵션으로 g를 붙이면 모두 변경
console.log(message2.replace(/\d{3}-\d{3,4}-\d{4}/g, "전화번호"));

search
const message = "안녕하세요. 010-1234-5678로 연락주세요.";
const message2 = `안녕하세요. 010-1234-5678말고, 010-9876-5432로 연락주세요.`
// 정규표현식 리터럴
const regExp = /\d{3}-\d{3,4}-\d{4}/;
// 무조건 처음 매칭된 것을 반환
console.log(message.search(regExp));
console.log(message2.search(regExp));
console.log(message2.search(/\d{3}-\d{3,4}-\d{4}/g));
//모두 탐색하려면 matchAll을 사용해야 함
console.log([...message2.matchAll(/\d{3}-\d{3,4}-\d{4}/g)]);

capture
const message = "안녕하세요. 010-1234-5678로 연락주세요.";
// 정규표현식 리터럴
const regExp = /(\d{3})-(\d{3,4})-(\d{4})/;
console.log(message.match(regExp));

Run-length encoding
-> A, B, C로 각각 그룹화됨을 알 수 있음const raw = "AAAAAABBBDFFFFFFFKK";
const compressed = "6A3B1D7F2K";
const regExp = /(.)\1*/g;
const result = raw
.match(regExp)
.reduce((a, b) =>
a + `${b.length}${b.slice(0, 1)}`, "");
console.log(result);
console.log(result === compressed);

HTTP 통신
Cookie
Set-Cookie
쿠키의 취약점
서버가 사용자를 구분하려면? >> Session
Session
세션의 문제점
이제는 서버와 클라이언트 간 인증은 별도 토큰을 사용하고, 쿠키는 클라이언트 자체적이고 지속적인 데이터 관리 용도로 많이 사용됨
웹스토리지
로컬 스토리지
세션 스토리지
// 쿠키 관리는 String으로. 불편
document.cookie = "key=value; key2=value2;"
// 데이터를 저장
localStorage.setItem('name', '이선협');
console.log(localStorage.getItem('name')); //이선협
// 데이터를 지움
localStorage.removeItem('name');
// 데이터를 전부 지움
localStorage.clear();
// 데이터를 저장
sessionStorage.setItem('name', '이선협');
console.log(sessionStorage.getItem('name')); //이선협
// 데이터를 지움
sessionStorage.removeItem('name');
// 데이터를 전부 지움
sessionStorage.clear();
HTML (Hyper Text Markup Language)
HTML은 이제 문서 구조(Structure)와 의미(Semantic)로만 남게 되었다
HTML5
※ 주의할 점!
-> 태그마다 기본 스타일이 있음
// 형식이 정해져있는 리스트 태그
<ul>
<li>Hello</li>
<li>HTML</li>
<li>CSS</li>
<li>JavaScript</li>
</ul>
Reset CSS 툴을 사용할 수 있음
https://meyerweb.com/eric/tools/css/reset

브라우저마다 미묘하게 기본 스타일이 다름
-> Normalize.css 를 사용할 수 있음
http://necolas.github.io/normalize.css
DOM (Document Object Model) : 문서 객체 모델
DOM은 왜 탄생했을까?

getElementById
- DOM Tree에서 요소 노드를 id로 찾음
- 제일 먼저 찾은 요소 하나를 반환
getElementByClassName
- DOM Tree에서 요소 노드를 class로 찾음
- 일치하는 모든 요소를 반환
getElementByTagName
- DOM Tree에서 요소 노드를 태그 이름으로 찾음
- 일치하는 모든 요소를 반환
querySelector
- DOM Tree에서 요소 노드를 CSS Selector 문법으로 찾음
- 제일 먼저 찾은 요소 하나를 반환
querySelectorAll
- DOM Tree에서 요소 노드를 CSS Selector 문법으로 찾음
- 일치하는 모든 요소를 반환
window.[id]
- id가 있는 요소는 window 객체를 통해 찾을 수 있음
- 여러 개라면 리스트로 반환
parentNode
- 선택한 요소 노드의 부모 노드를 불러옴
- document의 부모 노드는 null
firstElementNode
- 선택한 요소 노드의 자식 요소 노드 중 첫 번째를 불러옴
- 없을 경우 null을 반환
children
- 선택한 요소 노드의 자식 요소 노드를 불러옴
- 없을 경우 빈 배열을 반환
nextElementSibling
- 선택 요소 노드의 다음 형제 요소 노드를 불러옴
- 없을 경우 null을 반환
previousElementSibling
- 선택 요소 노드의 이전 형제 요소 노드를 불러옴
- 없을 경우 null을 반환
class 접근
- 선택한 요소 노드에서 className과 classList로 요소의 class 속성을 불러오고 변경할 수 있음
hasAttribute
- 선택한 노드에서 속성을 가지고 있는지 확인할 수 있음
setAttribute
- 선택한 노드에서 속성을 정의
removeAttribute
- 선택한 요소 노드에서 속성을 제거
textContent
- 선택한 요소 노드에서 텍스트 노드에 접근, 변경할 수 있음
innerHTML
- 선택한 요소 노드 내부 HTML을 수정
- XSS 위험이 있음 (사용 추천Xx)
createElement
- 요소 노드를 (태그 이름으로) 생성할 수 있음
appendChild
- 선택한 요소 노드 마지막 자식 요소로 추가
removeChild
- 선택한 요소 노드 자식 노드 중 해당하는 요소를 제거
virtual Dom이란?
한 번에 여러 개의 DOM 객체를 수정한다면?
-> DOM을 한번 조작할 때마다 다시 레이아웃을 잡고 렌더링 해야함
-> 만약, 한 번에 100개의 DOM을 수정해야한다면 최악의 경우 100번 렌더링을 해야할 수도 있음
Virtual DOM의 오해
virtual DOM은 DOM 보다 빠르다?
-> 간단한 에디터 css적용한 모습
<!DOCTYPE html>
<html>
<head>
<title>Simple Editor</title>
<link href="index.css" rel="stylesheet" type="text/css">
</head>
<body>
<div class="toolbar">
<button class="bold">Bold</button>
<button class="italic">Italic</button>
<button class="align-left">Align Left</button>
<button class="align-center">Align Center</button>
<button class="align-right">Align Right</button>
</div>
<!-- contenteditable : 이 영역 내에서 편집 가능 -->
<div class="editor" contenteditable="true"></div>
<script src="index.js"></script>
</body>
</html>
.toolbar {
width: 600px;
height: 40px;
padding: 8px;
border-radius: 4px;
background-color: bisque;
box-sizing: border-box;
}
.toolbar button {
height: 24px;
border: 2px solid black;
background-color: white;
cursor: pointer;
}
.toolbar button:hover {
background-color: gray;
}
.editor {
width: 600px;
height: 600px;
padding: 16px;
margin-top: 8px;
font-size: 12px;
border-radius: 4px;
border: 2px solid black;
outline: none;
box-sizing: border-box;
}
// 즉시 실행 함수
(() => {
document.querySelector(".bold").addEventListener("click", () => {
document.execCommand("bold");
});
document.querySelector(".italic").addEventListener("click", () => {
document.execCommand("italic");
});
document.querySelector(".align-left").addEventListener("click", () => {
document.execCommand("justifyLeft");
});
document.querySelector(".align-center").addEventListener("click", () => {
document.execCommand("justifyCenter");
});
document.querySelector(".align-right").addEventListener("click", () => {
document.execCommand("justifyRight");
});
})();
-> 보기가 너무 불편하고 하나로 묶어줄 수 있을 것 같음
<!DOCTYPE html>
<html>
<head>
<title>Simple Editor</title>
<link href="index.css" rel="stylesheet" type="text/css">
</head>
<body>
<div class="toolbar">
<button data-command="bold">Bold</button>
<button data-command="italic">Italic</button>
<button data-command="justifyLeft">Align Left</button>
<button data-command="justifyCenter">Align Center</button>
<button data-command="justifyRight">Align Right</button>
</div>
<!-- contenteditable : 이 영역 내에서 편집 가능 -->
<div class="editor" contenteditable="true"></div>
<script src="index.js"></script>
</body>
</html>
// 즉시 실행 함수
(() => {
document.querySelectorAll('.toolbar button').forEach(element => {
element.addEventListener('click', (e) => {
const command = e.target.getAttribute('data-command');
document.execCommand(command);
});
});
})();