728x90
try-catch
- 에러(Error)란, 컴퓨터 하드웨어의 오동작 또는 고장으로 인해 응용프로그램에 이상이 생기는 것을 말한다.
- 에러가 발생했을 경우 개발자가 대처할 방법이 극히 제한적이다.
- 예외란, 사용자의 잘못된 조작 또는 개발자의 잘못된 코딩으로 인해 발생하는 프로그램 오류이거나, 자바스크립트에서는 에러라고 인식하지 않아도 내가 생성한 함수의 규칙이 어긋나서 에러 처리를 하고 싶은 경우를 말한다.
- 에러와 예외의 공통점: 발생하면 프로그램이 종료된다.
- 에러와 예외의 차이점: 예외는 예외처리(Exception Handling)를 통해 프로그램을 종료 되지 않고 정상적으로 작동하게 만들어 준다.
- Try Catch문을 통해 Javascript에서도 예외처리가 가능하다.
- 프로그램의 안전성을 높일 수 있다.
- 구문
try {
//오휴가 발생할 것 같은 코드
} catch (error) {
//오류가 발생했을 때 이 자리로 들어온다.
//오류의 메세지 erroe 매개변수 처럼 이름을 바꿔도 된다.
}
throw
- 사용자 정의 예외를 발생(throw)할 수 있다.
- 예외가 발생하면 현재 함수의 실행이 중지되고 throw 이후의 명령문은 실행되지 않는다.
- 제어 흐름이 콜 스택의 첫 번째 catch 블록으로 전달된다.
- catch 블록이 없을 경우 프로그램이 종료된다.
//throw 문법
//expression: 예외를 발생시킬 표현식이다.
throw expression;
//예를들어,
throw 'Error2'; // 문자열 값을 가지는 예외 발생
throw 42; // 42 값을 가진 예외 발생
throw true; // true 값을 가지는 예외 발생
try {
//if문이 true 이므로 그 밑의 구문 실행
if(5 == 5)
//throw문이 실행되면서 if문을 빠져나오고
//throw메시지를 매개변수로 가지고 첫 번째 catch 이동
throw"Err발생"
} catch (error) {
console.log(error); //throw 메시지 출력
}
//결과: Err발생
function myStr(){
let devValue = document.querySelector('.dev').value;
try {
if(devValue =="")throw "비었음" //devValue가 비어있으면 오류메세지를 던져라
devValue = Number(devValue);
//number숫자로 타입을 변경해주는 생성자 함수
if(isNaN(devValue)) throw "number가 아님" //숫자가 아닌 값이 주어지면 오류메세지가 나옴
//문자열이 들어가면 숫자로 변환될 수 없어서 number가 아니다.
//오류가 발생을 해도 프로그램이 종료가 안된다.
} catch (error) {
//코드를 실행하다가 err가 발생하면
//catch문을 실행하고 오류의 내용은
//error매개변수에 들어온다.
console.log(typeof devValue) //결과: devValue 값이 공백- string / devValue 값이 숫자X- number
console.log(devValue) //결과: devValue 값이 공백- / devValue 값이 숫자X- NaN
document.querySelector(".message").innerHTML = error; //html의 message 클래스에 error의 내용을 던진다.
}
}
재귀함수
- 재귀함수란, 함수에서 함수 자신을 다시 호출하여 작업을 수행하는 방식을 말한다.
- 특정 분기까지 자기 자신을 계속해서 호출하여 사용한다.
- 반복문을 구현할 때 주로 사용한다.
- 함수가 자기 자신을 호출하기 때문에 무한으로 돌지 않으려면 얼마나 반복을 할 건지 명시해주어야 한다.
- 재귀 호출을 너무 많이 하게 되면 스택 오버플로가 발생할 수 있으니 주의하여야 한다.
- 쓸 일이 많지는 않을 것이지만 알고리즘 문제 등을 활용할 때 쓰이곤 한다.
- 임시로 데이터베이스에 추가할 때 사용할 수도 있다.
- 문법
function add(){
add();
}
- 함수 실행 컨텍스트를 기억해야 한다!
- 함수가 호출되면 실행 컨텍스트가 생성되고, 함수 안에서 함수를 호출하면서 실행 컨텍스트가 쌓이고 뒤에서부터 실행하고 실행 컨텍스트를 제거한다.
function add(n){
if(n < 5){
add(n + 1);
console.log(n);
//결과: 4 3 2 1 0
}
}
add(0);
👩🏫예시_ 파보니치 수열
파보니치 수열
- 수학에서 다루는 수열이다.
- 어떤 수열의 항이 앞의 두 항의 합과 같은 수열을 말한다.
- 재귀함수로 파보니치 수열을 만들어보자.
function fibonacci(n){
if(n < 2) return n;
//이전 두 항을 더해서 반환
//(n - 1) 이전 항 / (n - 2) 이이전 항
return fibonacci(n - 1) + fibonacci(n - 2);
}
for (let i = 0; i < 20; i++) { //결과 값을 20개 가진다.
console.log(fibonacci(i));
//결과: 0, 1, 1, 2, 3, 5, 8, 13, 21, ..., 4181
}
promise 객체
- 비동기 처리를 가능하게 해주는 객체이다.
- 비동기 처리: 특정 코드의 실행이 완료될 때까지 기다리지 않고 다음 코드를 먼저 수행하는 자바스크립트의 특성
- 주로 서버에서 받아온 데이터를 화면에 표시할 때 사용한다
- 프로미스의 생성
- 예) return new Promise(function(resolve, reject){ } )
- new Promise(): new 키워드로 빈 객체를 만들고 promise 객체를 생성한다.
- resolve(value): 일이 성공적으로 끝난 경우 그 결과를 나타내는 value와 함께 호출
- reject(error): 에러 발생 시 에러 객체를 나타내는 error와 함께 호출된다.
프로미스의 3가지 상태(states)
- 프로미스를 사용할 때 알아야하는 가장 기본적인 개념이다.
- 프로미스의 상태: 프로미스의 처리 과정을 의미한다.
- new Primise( )로 프로미스를 생성하고 종료될 때까지 3가지의 상태를 갖는다.
Pending(대기)
- 비동기 처리 로직이 아직 완료되지 않은 상태
- new Promise() 메서드를 호출할 때 콜백 함수를 선언할 수 있고, 콜백 함수의 인자는 resolve, reject이다.
//아래와 같이 메서드를 호출하면 대기 상태가 된다.
new Promise();
//콜백함수로 선언할 수 있으며, 콜백 함수의 인자는 resolve, reject이다.
new Promise(function(resolve, reject) {
// ...
});
Fulfilled(이행)
- 비동기 처리가 완료되어 프로미스가 결과 값을 반환해준 상태
//콜백 함수의 인자를 실행하면 이행 상태가 된다.
new Promise(function(resolve, reject) {
resolve();
});
//이행 상태가 되면 then()을 이용해서 처리 결과 값을 받을 수 있다.
function getData() {
return new Promise(function(resolve, reject) {
var data = 100;
resolve(data);
});
}
// resolve()의 결과 값 data를 resolvedData로 받음
getData().then(function(resolvedData) {
console.log(resolvedData); // 100
});
Rejected(실패)
- 비동기 처리가 실패하거나 오류가 발생한 상태
//new Promise()로 생성하면 콜백 함수 인자로 resolve와 reject를 사용할 수 있는데
//아래와 같이 호출하게 되면 실패 상태가 된다.
new Promise(function(resolve, reject) {
reject();
});
//실패 상태가 되면 실패한 이유로, 실패 처리의 결과 값을 catch()로 받을 수 있다.
function getData() {
return new Promise(function(resolve, reject) {
reject(new Error("Request is failed"));
});
}
// reject()의 결과 값 Error를 err에 받음
getData().then().catch(function(err) {
console.log(err); // Error: Request is failed
});
.then() / .catch() / .finally()
.then()
- promise에서 가장 중요하고 기본이 되는 메소드.
- .then( )의 인수
- .then의 첫 번째 인수: promise()가 이행되었을 때 실행되는 함수. 실행 결과를 받는다.
- .then의 두 번째 인수: promise()가 거부되었을 때 실행되는 함수. 에러를 받는다.
//성공적으로 작업을 수행한 promise의 경우
let promise = new Promise(function(resolve, reject) {
setTimeout(() => resolve("완료!"), 1000);
});
// resolve 함수는 .then의 첫 번째 함수(인수)를 실행합니다.
promise.then(
result => alert(result), // 1초 후 "완료!"를 출력
error => alert(error) // 실행되지 않음
);
//promise가 거부된 경우
let promise = new Promise(function(resolve, reject) {
setTimeout(() => reject(new Error("에러 발생!")), 1000);
});
// reject 함수는 .then의 두 번째 함수를 실행합니다.
promise.then(
result => alert(result), // 실행되지 않음
error => alert(error) // 1초 후 "Error: 에러 발생!"을 출력
);
//작업이 성공적으로 처리된 경우만 가루고 싶다면 인수를 하나만 전달하면 된다.
let promise = new Promise(resolve => {
setTimeout(() => resolve("완료!"), 1000);
});
promise.then(alert); // 1초 뒤 "완료!" 출력
.catch()
- 에러가 발생한 경우만 다루는 메소드
- .then()의 첫 번째 인수에 null값을 전달하면 동일하게 작동하기도 한다.
- .catch()는 문법이 간결하다는 점만 빼면 .then(null, f)과 완벽하게 같다.
let promise = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error("에러 발생!")), 1000);
});
// .catch(f)는 promise.then(null, f)과 동일하게 작동합니다
promise.catch(alert); // 1초 뒤 "Error: 에러 발생!" 출력
.finally()
- promise가 처리(이행 or 거부)되면 항상 ' f '가 실행된다는 점에서 .finally(f) 호출은 .then(f, f)과 유사하다.
- .then(f, f)과의 차이점
- finally()에는 인수가 없다.
- finally에선 프라미스가 이행되었는지, 거부되었는지 알 수 없다.
- finally에선 절차를 마무리하는 ‘보편적’ 동작을 수행하기 때문에 성공·실패 여부를 몰라도 다.
- .finally(f)는 함수 f를 중복해서 쓸 필요가 없기 때문에 .then(f, f)보다 문법 측면에서 더 편리다.
- finally()에는 인수가 없다.
- .then(f, f)과의 차이점
- 결과가 어떻든 마무리가 필요하면 finally가 유용하다.
new Promise((resolve, reject) => {
/* 시간이 걸리는 어떤 일을 수행하고, 그 후 resolve, reject를 호출함 */
})
// 성공·실패 여부와 상관없이 프라미스가 처리되면 실행됨
.finally(() => 로딩 인디케이터 중지)
.then(result => result와 err 보여줌 => error 보여줌)
async / await
- (then, catch)와 (async, await)를 절대로 같이 사용하지 말자.
- 같이 사용한다는 것은 promise를 잘 모른다는 뜻이다.
- 같이 써도 잘 돌아가긴 하지만 좋지 않은 버릇이다.
async 함수
- function 앞에 위치한다.
- 항상 promise를 반환한다.
- promise가 아닌 값을 반환하더라도 이행 상태의 promise로 값을 감싸 이행된 promise가 반환되도록 한다.
//promise가 아닌 값을 반환
async function f() {
return 1;
}
f().then(alert);
// 결과: 1
//promise를 명시적으로 반환
async function f() {
return Promise.resolve(1);
}
f().then(alert);
// 결과: 1
await 함수
- async 함수 안에서만 동작한다.
- 일반 함수 내에서는 사용할 수 없다.
- 자바스크립트에서 await 키워드를 만나면 promise가 처리될 때까지 기다린다.
async function f() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("완료!"), 1000)
});
let result = await promise; // 프라미스가 이행될 때까지 기다림 (*)
alert(result); // "완료!"
}
f();
- await는 최상위 레벨 코드에서 작동하지 않는다.
// 최상위 레벨 코드에선 문법 에러가 발생함
let response = await fetch('/article/promise-chaining/user.json');
let user = await response.json();
// 익명 async 함수로 코드를 감싸면 최상위 레벨 코드에도 await를 사용할 수 있다.
(async () => {
let response = await fetch('/article/promise-chaining/user.json');
let user = await response.json();
...
})();
👩🏫Promise 예시_1
function testPromise(num){
//new 키워드로 빈 객체를 만들고
//promise 객체를 생성
//전달하는 함수 값에 resolve , reject 두 가지의 매개변수를 받는데
// resolve() 함수고 처리가 완료되면 반환
// reject() 함수고 처리가 오류나면 반환
return new Promise(function(res, rej){
try {
if(num > 10)
rej({date : "숫자 큼"}); //if문 영역
//if의 중괄호가 없으면 바로 및 코드까지 조건문 영역
// console.log(num);
//데이터를 받아온다고 가정을 하자.
//데이터를 가져오는 시간이 좀 걸리는데
//데이터를 다 가져오고 작업을 진행시켜야 할 때.
setTimeout(function(){
// res(num);
res(num + 10);
},num * 1000)
} catch (error) {
rej(error);
}
})
}
testPromise(8).then(function(date){
//데이터를 가져오고 처리할 구문을 여기에 작성하면 된다.
//데이터를 가지고 처리해야할 작업
return testPromise(date);
}).then(function(date){
console.log(date);
//성공
//res를 실행하면 then() 메소드가 실행되고
//결과: 18
}).catch(function(err){
console.log(err);
//실패
//rej을 실행하면 catch() 메소드가 실행된다.
//결과:{date: '숫자 큼'}
})
👩🏫Promise 예시_2
function testPromise(num){
//new 키워드로 빈 객체를 만들고
//promise 객체를 생성
//전달하는 함수 값에 resolve , reject 두 가지의 매개변수를 받는데
// resolve() 함수고 처리가 완료되면 반환
// reject() 함수고 처리가 오류나면 반환
return new Promise(function(res, rej){
try {
// 2.❗num의 값이 10보다 작으므로 setTimeout 으로 진행
// 7.❗num의 값이 10보다 크르모 rej의 값인 date를 가지고 진행된다.
if(num > 10)
rej({date : "숫자 큼"}); //if문 영역
//if의 중괄호가 없으면 바로 및 코드까지 조건문 영역
//데이터를 받아온다고 가정을 하자.
//데이터를 가져오는 시간이 좀 걸리는데
//데이터를 다 가져오고 작업을 진행시켜야 할 때.
// 3.❗5초의 시간을 기다리면 15의 결과값이 asyncFun 함수로 반환
// 8.❗setTimeout을 지나가고 다시 복귀
setTimeout(function(){
res(num + 10);
},num * 1000)
} catch (error) {
rej(error);
}
})
}
async function asyncFun(){
//이제 왠만하면 try catch로 작업의 오류를 예외상황을 잡으면서 작업하자.
try {
//await뒤에 pormise 객체
/* 1.❗ await 메소드는 promise가 처리될 때 까지 기다리고 결과값을
그 이후에 반환하므로 promise 함수로 올라가 매개변수 num에 5의 값을 대입 */
let tmep = await testPromise(5);
//결과: 5
//기다리고 promise객체 res나 rej이 처리될 때까지
//4.❗ promise함수에서 돌아오고 실행하는 console 값 1을 노출한다.
console.log(1);
//결과:(5초 뒤에) 1
/*5.❗ promise함수에서 리턴받은 tmep 값을 출력. 15가 노출된다.
(시간이 소요되는 것은 promise 함수를 실행할 때 동작하였으므로
위에 콘솔과 동일한 시간에 노출이 진행된다.) */
console.log(tmep);
//결과:(5초 뒤에) 15
//6.❗ await 함수가 다시 promise 함수를 실행시켜 현재 값인 15를 가지고 올라간다.
tmep = await testPromise(tmep);
console.log(tmep);
//결과:(5초 뒤에) 15
//await + promise = promise를 기다리고 resolce값을 반환한다.
//async await는 짝이다. 같이 써야한다.
//9.❗error값을 date:'숫자 큼' 으로 받아와 노출한다.
} catch (error) {
console.log(error);
}
}
asyncFun();
정규 표현식(RegExp) 객체
- 문자열에서 특정 문자 조합을 찾기 위한 패턴이다.
- 예) 회원가입 email id 주소 같은 형식으로 입력하기 위해 문자의 패턴을 정의하는데 유용하다.
정규 표현식 만들기
정규 표현식 리터럴( / / )
- 슬래시로 패턴을 감싸서 작성한다.
- 스크립트를 불러올 때 컴파일 되므로, 바뀔 일이 없는 패턴의 경우 성능이 향상될 수 있다.
RegExp
- RegExp 객체의 생성자 호출
- 생성자 함수를 사용하면 정규 표현식이 런타임에 컴파일 되므로, 바뀔 수 있는 패턴이나 사용자 입력 등 외부 출처에서 가져오는 패턴의 경우 사용하기 좋다.
//정규 표현식
let reg1 = /a/; //정규 표현식 객체를 선언하는 방법 1
let reg2 = new RegExp('a'); //정규 표현식 객체를 선언하는 방법 2
search( ), replase( ), test( ), match() 메소드
search( )
- 정규 표현식과 string 객체간에 같은 것을 찾기 위한 검색을 실행한다.
- 정규표현식과 주어진 스트링간에 첫 번째로 매치되는 것의 인덱스를 반환한다.
- 찾지 못하면 -1을 반환한다.
let str = "Hello Javascript Program...";
//search 해당 문자열의 위치를 찾는 메소드
let regExp_search = str.search(/Javascript/);
console.log(regExp_search);
//결과: 6 (Javascript)의 시작 인덱스를 찾아준다.
replase( )
- 어떤 패턴에 일치하는 일부 또는 모든 부분이 교체된 새로운 문자열을 반환한다.
- 여기서 말하는 패턴은 문자열이나 정규식이 될 수 있다.
- 교체 문자열은 문자열이나 모든 매치에 대해서 호출된 함수일 수 있다.
- 패턴이 문자열일 경우, 첫 번째 문자열만 치환이 되며 원래의 문자열은 변경되지 않는다.
- 교체 될 문자열은 오직 첫 번째로 일치하는 문자열만이 교체가 가능하다.
- 호출된 string 객체는 바꾸지 않는다. 새로운 문자열을 리턴하는 것이다.
let str = "Hello Javascript Program...";
let RegExp_replace = str.replace(/Javascript/, 'CSS');
console.log(RegExp_replace);
//결과: Hello CSS Program...
//replace 첫 번째 매개변수로 전달한 문자열을 찾아서
//두 번째 매개변술 전달한 문자열로 바꿔준다.
test( )
- 주어진 문자열이 정규 표현식을 만족하는지 판별하고, 그 여부를 true, false로 반환한다.
let str = "Hello Javascript Program...";
let reg3 = /Javascript/;
console.log(reg3.test(str));
//결과: true (문자열이 있으면 true)
let reg4 = /Javascript2/;
console.log(reg4.test(str));
//결과: false (문자열이 없으면 false)
match( )
- 해당되는 문자열을 찾고 배열의 형태로 반환해준다.
- 일치하는 값이 없으면 null을 반환한다.
let str2 = 'The best program is \n JavaScript...';
//플래그는 정규식 뒤에 붙인다.
let tmep1 = /javascript/i;
console.log(str2.match(tmep1));
/*결과
['JavaScript', index: 22, input: 'The best program is \n JavaScript...', groups: undefined]
0: "JavaScript"
groups: undefined
index: 22
input: "The best program is \n JavaScript..."
length: 1
[[Prototype]]
:
Array(0)
*/
정규 표현식의 플래그
- 정규 표현식은 전역 탐색이나 대소문자 무시와 같은 특성을 지정하는 플래그를 가질 수 있다.
- 플래그는 단독으로 사용할 수 있고, 순서에 상관없이 한꺼번에 여러개를 지정하여 사용할 수도 있다.
- i : 대소문자를 구분하지 않고 검색한다. (A와 a에 차이가 없다.)
- g : 전체 문자열을 정규식과 비교한다. 첫 번째로 일치한 문자열이 있으면 비교를 중지한다.
- m : 줄이 다른 여러 줄의 문자열을 정규 표현식으로 비교한다.
- d : 부분 문자열 일치에 대해 인덱스를 생성한다.
- s : ' . (점)'이 개행문자 \n도 포함하도록 dotall 모드를 활성화한다.
- 기본적으로 점은 \n과 일치하지 않는다. 때문에 /A.B/는 A와 B사이에 \n을 제외한 모든 들어간 문자열과 일치한다.
- 하지만 플래그 s를 사용하면 \n을 포함한 모든 문자열이 일치하게 된다.
- u : 유니코드 전체를 지원한다.
- y : 문자 내 측정 위치에서 검색을 진행하는 'sticky'모드를 활성화 시킨다.
let str = 'The best program is \n JavaScript...';
//플래그는 정규식 뒤에 붙인다.
// i 플래그는 대소문자를 구분하지 않는다.
let tmep1 = /javascript/i;
console.log(str.match(tmep1));
//결과: ['JavaScript', index: 22, input: 'The best program is \n JavaScript...', groups: undefined]
//g 플래그는 전체 문자열을 정규식과 비교한다.
let temp2 = /Javascript/g;
console.log(str.match(temp2));
//결과: null (문자열을 찾지 못하면 (Java'S'cript 가 맞음))
let temp3 = /JavaScript/g;
console.log(str.match(temp3));
/*결과
['JavaScript']
0: "JavaScript"
length: 1
*/
//m플래그는 줄이 다른 문자열을 비교한다.
let temp4 = /JavaScript/m;
console.log(str.match(temp4));
/*결과
['JavaScript', index: 22, input: 'The best program is \n JavaScript...', groups: undefined]
0: "JavaScript"
groups: undefined
index: 22
input: "The best program is \n JavaScript..."
length: 1
*/
//s플래그는 모든 문자를 찾아 일치하게 만든다.
alert( "A\nB".match(/A.B/) );
// null (일치하지 않음)
alert( "A\nB".match(/A.B/s) );
// A\nB (일치!)
정규식의 패턴
- [abc]: 대괄호 안에 있는 문자들을 찾는다.
- [0-9]: 대괄호 사이의 숫자를 찾는다.
- [x|y]: 문자 중에서 ' | '로 분리된 문자 중 하나를 찾는다.
let str = "The best program id Java123Script and 456HTML..."
let tmep5 = /Java123Script/ig;
//플래그 ig를 썼기 때문에 대 소문자 구분없이 'JavaScript'만 가져왔다.
console.log(str.match(tmep5));
/*결과
['Java123Script']
0: "Java123Script"
length: 1
*/
//문자열 안에 해당하는 알파벳을 다 찾아온다.
let temp6 = /[A-K]/ig;
console.log(str.match(temp6));
//결과: (16) ['h', 'e', 'b', 'e', 'g', 'a', 'i', 'd', 'J', 'a', 'a', 'c', 'i', 'a', 'd', 'H']
//분리된 문자열을 가져온다.
let temp7 = /p|x|z/ig;
console.log(str.match(temp7));
/*결과
(2) ['p', 'p']
0: "p"
1: "p"
length: 2
*/
정규식에서의 메타문자
- 메타문자는 숫자만이거나 알파벳만이거나 아니면 숫자를 제외하거나 등의 속성을 표현한다.
- 메타문자는 단순 문자가 아닌 다른 용도로 사용되는 문자를 말하며, 단일 문자 또는 ' \ + 단일문자 '의 형태로 사용.
- ^문자: 정규식으로 시작 문자를 찾는다. ^뒤에 있는 문자로 시작하는 문자를 찾는다.
- 문자$ : 정규식으로 끝나는 문자를 찾는다. $앞에 문자로 끝나는 문자열을 찾는다.
- \w(소문자) : 모든 문자를 찾는다. 속하는 모든 문자를 찾는다.
- \W(대문자) : 알파벳 대소문자, 숫자, _(언더바) 를 제외한 모든 문자를 찾는다.
- \d(소문자) : 숫자를 찾는다.
- \D(대문자) : 숫자를 제외하고 찾는 것이다. (숫자를 제외한 모든 문자를 찾는다.)
- \s(소문자) : 공백 문자를 찾는다.
- \S(대문자) : 공백 문자를 제외하고 찾는다.
let str = "The best program id Java123Script and 456HTML..."
let temp8 = /^J/ig;
console.log(str.match(temp8));
//결과: null (전체 문자열이 J로 시작하지 않기 때문이다.)
//문자열이 T로 시작하는지 확인을 하고 T가 맞으니까 맞는 문자열을 반환
let temp9 = /^T/ig;
console.log(str.match(temp9));
/*결과
['T']
0: "T"
length: 1
*/
let temp10 = /\d/ig;
console.log(str.match(temp10));
//결과: (6) ['1', '2', '3', '4', '5', '6']
더보기
- try-catch
- throw
- promise 객체
- 정규 표현식
- https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Regular_Expressions
- https://zephyrus1111.tistory.com/310
- https://ko.javascript.info/regexp-character-classes
- https://ko.javascript.info/regexp-introduction
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes
728x90