2026년 2월 11일 수요일 - 7주차
- 명명 함수: 당연히 프로그램 언어라면 존재해야하는 기본적인 방법이다. 고전, 트랜드 그런거 상관 없이 모든것의 기초가 되는 방식.
- 예시: function 함수명(매개변수) { 함수 내부 }
- 익명 함수(Anonymous Function): 고전 방식. 함수명을 생성하지 않고 변수에 넣는다. 변수명이 함수명을 대신함.
- 예시: const test2 = function(매개변수) { 함수 내부 };
- 화살표 함수(Arrow Function): 트랜디한 방식. ES6에서 나온 방식이며, 람다식을 쓸 수 있게 해준다.
- 예시: const test3 = (매개변수) => { 함수 내부 };
콜백함수: 내가 만든 함수를 내가 호출하지 않고 남이 호출하는 것. 즉, 만들어둔 함수를 직접적인 호출문이 아니라 함수의 내부, 혹은 매개변수 안에서 사용하는 것이다.
콜백함수의 예시는 호출하는 함수는 매개변수를 2개 가지며, 첫번째 매개변수는 콜백함수, 두번째 함수는 숫자라고 가정하고 진행된다.
이렇게 콜백 함수를 필요로 하는 함수를 사용할 때, 몇줄 되지 않는 코드를 위해 함수를 상단에 따로 정의 하는것 보다 직접 그 자리에서 정의하는것이 편하기 때문에 문법이 나왔다.
먼저, 기본적인 콜백함수의 사용법은 함수명(매개변수1(함수), 매개변수2); 이 형태이며, 아래의 두개의 함수를 쓰다보면 결국 이쪽으로 돌아온다고 하긴 한다..
- 익명 함수를 사용하는 콜백 함수 사용법:
함수명(finction(매개변수) { 함수 내부 }, 300);- 화살표 함수를 사용하는 콜백 함수 사용법:
함수명((매개변수) => { 함수 내부 }, 300);
[06 함수2.html]
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
function test1() {
console.log("test1 호출됨!");
return a + b;
}
const bbb = test1(1, 2); // 이거랑 아래는 다른것이란것을 명확히 알기.
const aaa = test1; // 이거는 aaa가 함수를 호출하는게 아니라 aaa변수에 함수를 담는것이다.
aaa(1, 3); // 그래서 이게 된다. 이제부터 aaa는 test1 함수인것.
test1(4, 5) // 이건 그냥 함수 호출하는거.
// 이런걸 콜백함수라고 부른다.
setTimeout(test1, 3000);
// 함수를 정의하는 3가지 방법.
// 1. 명명 함수 - 당연히 있어야 하는것.
function test2() {
}
test2();
// 2. 익명 함수(고전 방식)
const test3 = function() {
};
test3(); // 이 변수는 test3 함수를 가르키는 변수가 된다.
// 3. 화살표 함수
const test4 = () => {
};
test4();
// 콜백 함수 사용법
// 기본적인 콜백함수 사용 법
setTimeout(test2, 3000);
// 1. 익명함수.
setTimeout(function() {
console.log("안녕하세요.");
}, 3000);
// 2. 화살표 함수. (제일 많이 쓰임)
setTimeout(() => {
console.log("안녕하세요");
}, 3000);
</script>
</head>
<body>
</body>
</html>
함수 자체는 값(일급 객체)이 되고, 그걸 변수에 담을 수 있다.
- 고차 함수: 파라미터 혹은 리턴을 함수로 받거나 리턴해주는 함수이다. 문법적으로 고차함수가 있는건 아니고, 개념적인 것이다. 백엔드 API는 고차함수가 많지는 않은데(람다식이 고차함수), 프론트의 API는 죄다 고차함수이다.
- 정의: function 함수명(매개변수1, 매개변수2) { 함수1(매개변수); 함수2(매개변수); reutrn (매개변수) => { 함수 내부 }; }; - 호출: test1((함수1의 매개변수) => { 함수1의 함수 내부 }, (함수2의 매개변수) => { 함수2의 함수 내부 });
[07 함수3.html]
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
// 고차 함수
function test1(a, b) {
a();
b();
return () => {
console.log("야호!!");
};
}
test1(() => { // test1 함수 호출하는 부분. 매개변수 2개니까 파라미터 2개 줘야 함.
console.log("안녕하세요"); // 여기가 test1 함수의 첫번째 매개변수
}, () => { // , 있는 이유는 매개변수가 2개라는 뜻임
console.log("반갑습니다"); // 여기가 test1 함수의 두번째 매개변수
});
// 이거는 아마 받아온 리턴값을 출력하는..?
const result = test1(() => {
console.log("야호!!");
}, () => {
console.log("반갑습니다");
});
</script>
</head>
<body>
</body>
</html>
[08 클로저.html]
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
// 클로저. 사실 자바에도 클로저가 있고, 써봤지만 자세히 설명하지 않고 넘어갔다.
const a1 = 10;
const test1 = (v1, v2) => {
console.log("Hello!!");
console.log(`두 값의 합: ${v1+a1}`);
};
test1(3);
// 매개변수로 3, a1을 주는게 아니라, 3 하나만 보내고 위에있는 변수 a1을 함수가 직접 가져와서 쓰는 것.
// 원래는 스코프가 달라서 쓸수 없지만 클로저 문법을 통해 가능하게 만들었다.
// 프론트엔드는 대부분이 비동기식으로 진행된다. Java의 쓰레드 생각하면 된다.
// 그렇기 때문에 공유되는 자원이 생기기 때문에 하나의 공유된 메모리를 가둬두는 것이다.
// 비동기식 함수의 대표 예시: setTimeout
for(i = 0; i < 10; i++) {
setTimeout(() => {
console.log(i); // 이것도 클로저문법 사용하는 것
}, 3000); // 실행해보면 3초 후 1~10이 다 나오지 않고 10이 10번 출력된다. 공유된 자원 클로저라 이미 10이 다 증가되고 출력하기 때문에.
}
// 중간치 클로저
for(i = 0; i < 10; i++) {
const a = i; // 이렇게 const로 공유된 자원 i를 묶어버리면 메모리가 10개가 생성돼서 문제 없이 10번 나온다.
setTimeout(() => {
console.log(a);
}, 3000);
}
for(i = 0; i < 10; i++) {
setTimeout(processData(i), 5000)
}
// 최대치 클로저 - 매개변수를 클로저로 만듬
function processData(value) { // 고차함수 + 클로저
console.log("qqqqqqqqq"); // 얘는 setTimeout이랑 상관 없이 바로 10번 출력된다.
return () => { // setTimeout는 return된 값을 받아서 출력하기 때문에.
console.log(`processData: ${value}`); // 여기 있는 value는 클로저가 됨. 이 함수가 소멸되기 전까지 살아남아있음
}
}
</script>
</head>
<body>
</body>
</html>
[09 객체.html]
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
// JavaScript 객체와 JSON
const aaa = { // 이게 하나의 인스턴스를 생성하는 것. 클래스를 만들지 않고도 만들 수 있다. 구조 및 값을 한번에 세팅하는 것.
name: "민수", // 필드들
age: 30,
score: [70, 80, 90],
study: () => {
console.log("공부를 합니다");
},
family: [{
name: "엄마"
}, {}]
};
console.log(aaa);
console.log(aaa.name);
console.log(aaa.age);
console.log(aaa.score);
aaa.study();
// 위의 내용만으로도 충분함. 아래는 추가사항
console.log(aaa.qwer); // 이상하지만 런타임 에러는 아님. 쓸 일 거의 없음
aaa.yyyy = 30; // 더 이상하지만 잘 된다. 에러가 아님. 없던 필드를 생성한다
console.log(aaa);
// JSON (JavaScript Object Notation) = 데이터를 주고받기 위한, 문자열 표준(전세계 표준)
// 각 모든 언어는 클래스 인스턴스 데이터를 JSON 기반으로 변환하는(직렬화, 역직렬화) API가 존재한다
console.log(aaa);
const jsonText = JSON.stringify(aaa); // JS용 JSON 직렬화 API
console.log(jsonText);
const qqqqq = JSON.parse(jsonText); // JS용 JSON 역직렬화 (문자열을 JS 오브젝트로 변환)
</script>
</head>
<body>
</body>
</html>
[10 자료구조로의 Map.html]
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
// 자료 구조 Map
const qwer = {}; // 비어있는 Map 생성 java에서는 new hashMap
// 이 둘은 완벽하게 동일히다. push
// qwer.aaa = 10; // 객체 활용 문법
qwer["aaa"] = 10; // Map으로 활용하는 문법.
// get
console.log(qwer.aaa); // 두개 다 똑같은거지만 객체로 활용할거면 이거,
console.log(qwer["aaa"]); // Map으로 활용할거면 이거를 써야 한다.
</script>
</head>
<body>
</body>
</html>
[11 클래스(고전).html]
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
// ES5 이전 클래스. 원래 OOL이 아니었기 때문에 명확히 보면 클래스가 아니다..
// 그냥 이런게 있었구나 정도로만 이해하고 넘어가도 됨
function qwer() {
console.log("안녕하세요");
return 10;
}
const a1 = qwer();
const a2 = new qwer();
console.log(a3)
function Student(name, age, score) { // 함수지만 class로 쓸거기 때문에 파스칼 케이스 사용. (관례 문제)
this.name = "name";
this.age = age;
this.score= score;
// this.study = function () {
// console.log(`${this.name}이 공부를 합니다.`);
// };
}
// 메서드는 prototype에 구현
Student.prototype.study = function () {
console.log(`${this.name}이 공부를 합니다.`);
}
// static 함수(클래스?)에 바로 붙인다.
Student.someStaticMethod = function () {
}
const s1 = new Student("민수", 24, 45);
const s2 = new Student("트레이서", 21, 88);
console.log(s1);
console.log(s1);
s1.study();
s2.study();
</script>
</head>
<body>
</body>
</html>
[12 클래스 ES6.html]
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
// 클래스 문법(ES6) - 이제 조금 Java의 클래스랑 비슷해졌다.
class Student {
// #이 들어가면 private이다.
#name;
#age;
#score;
constructor(name, age, score) { // 셍성자 및 필드
this.name = name;
this.age = age;
this.score = score;
}
// 메서드 - 근데 리턴타입은 존재X
study() {
console.log(`${this.name}이 공부를 합니다.`);
}
// 스태틱 메서드
static test1() {
console.log("스태틱 메서드");
}
get name() {
return this.#name;
}
set name(name) {
if(name.includes("하하")) {
throw new Error("이름에 하하는 들어 갈 수 없습니다.");
// setter의 의도는 유효성 검사인데, 입력할때 setter가 자동으로 호출되기 때문에 자동으로 유효성 검사가 된다.
}
console.log("세터 호출 됨!!");
this.#name = name;
} // 이러면 setter를 호출 안해도 됨.
}
const s1 = new Student("민수", 25, 85);
const s2 = new Student("민수", 25, 85);
s1.study();
s2.study();
// s1.name = 30;
Student.test1();
console.log(s1.name);
s1.name = "영수"; // 이름 변경시킴. 이때 setter가 호출 됨.
console.log(s1.name);
</script>
</head>
<body>
</body>
</html>
[13 프로미스.html]
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
// 프로미스(ES6) - 매우 중요, 잘 써야 함. 근데 비동기 API를 써야 하는데 지금은 쉽지 않아서 조금 억지로 함.
// ㄴ 이후 버전에서 async/wait로 쉽게 가능해졌다.
// 리엑트 가면 처음부터 끝까지 이 코드임. 리엑트 아니어도 비슷.
// 비동기식 실행 (쓰레드)
const promise1 = new Promise((resolve, reject) => {
// 여기는 비동기로 바로 즉시 실행됨.
// 여기가 지금 5초정도 걸리는 복잡한 코드라고 가정... 여기서 일 시켜놓고 결과가 돌아올때까지 아래의 코드 실행시키고 있다가 결과가 나오면 이어서 처리하는 것이다.
// Java의 CompletableFuture랑 동일
console.log("AAAAAA");
resolve(33); // 과정이 끝난 후 결과 값. (return 느낌)
});
promise1.then((result) => {
// 위에 프로미스가 끝나고 난 뒤에 자동으로 실행 될 코드. result = resolve 값
console.log(result);
}); // catch, final 등등 가능함.
console.log("BBBBBB");
// 이제 AAAAAA가 먼저 실행될지, BBBBBB가 먼저 실행 될 지 모름. 높은 확률로 AAAAAA이긴 하겠지만 확신 불가능.
// 위에처럼 then을 따로 쓰는게 아니라 한번에 같이 쓰는게 더 일반적이긴 함.
// 물론 비동기로 실행되고 끝나는 코드의 경우에는 then, catch 등등 안해줘도 된다..
new Promise((resolve, reject) => {
console.log("AAAAAA");
resolve(33);
}).then(result => {
console.log(result);
}).catch(err => {
console.log("에러발생");
});
</script>
</head>
<body>
</body>
</html>
[14 async, await.html]
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
// async, await
// 동기식 함수
function test1() {
// 부동산 관련 내용처리
}
// 동기식 함수
function test2() {
// 차량 관련 내용처리
}
// 이렇게 서로가 다른 내용을 처리하고 있을때 비동기화로 쓸 수 있다. 단, 서로가 절대 엮이면 안된다.
// test1 끝나야 test2 시작됨
test1(); // 동기식 호출
test2(); // 동기식 호출
//////////////////////////////////////////////////////////////////////////////
// 비동기식 함수 async 붙이면 끝.
async function test3() {
// 부동산 관련 내용처리
return 1551;
}
// 비동기식 함수
function test3() {
// 차량 관련 내용처리
}
// test3, test4 동시에 다 호출 시키고 다 각자 돈다.
test3(); // 비동기식 호출
test4().then(result => { // 비동기식 호출
// test4() 코드 실행 이후에 실행 될 코드 retun 값을 받을 수 있음
console.log(result);
}).catch(err => {
// 예외처리
});
// async 함수를 호출시키면 Promise를 리턴해줌. 그래서 그 호출문 자체가 Promise가 된다. 바로 then, catch 붙일 수 있음.
// 그렇기 때문에 '변수 = ' 해서 값 받는게 아닌 then으로 받는다.
//////////////////////////////////////////////////////////////////////////////
// 만약 비동기 함수 test3, test4가 동기식(순차적)으로 호출 되었으면 할때는? - ex) test3이 먼저 끝나고, test4가 끝났으면 좋겠을때
// 첫번째 방법 - then을 이용.
test3().then(() => {
test4();
});
// 비동기 API를 순차적으로 쓰고 싶으면 위 코드 안에 계속 then으로 넣으면서 해도 되긴 한데,
// 이거 다 콜백 함수라서 이러면 콜백 지옥에 빠지는 케이스가 된다. 그래서 나온게 await.
// 두번째 방법 - await
// 비동기 함수를 동기식으로 호출.. 리턴타입은 더이상 promise가 아니고, return 값 그대로 받을 수 있음.
// await 함수에는 조건이 하나 있는데, await를 쓰는 애가 비동기 함수여야 한다.
// await test3();
// await test4(); 이러면 안됨.
// 그래서 그 함수들을 묶을 async 함수가 하나 필요함.
async function some() {
const result = await test3(); // 비동기 함수를 동기식으로 호출 - 여기서 test3이 끝날때까지 기다림.
await test4(); // 비동기 함수를 동기식으로 호출 - 더이상 문법적으로 promise가 아니게 되기 때문에 then, catch를 쓸 수 없다. 그래서 예외 try-catch문으로 잡음
}
</script>
</head>
<body>
</body>
</html>
[15 내장 API.html]
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
// 전역 객체
// window. location, document(가장 중요), history, navigator
// 나중에 이 API 다 뭔지 좀 찾아서 쓰기
</script>
</head>
<body>
</body>
</html>