
Float가 없음!! const user = Symbol(); # 선언
const user = Symbol('this is a user'); # 설명을 붙여서 선언
# 어떤 값과 비교해도 true가 될 수 없는 고유한 변수가 됨
const user = Symbol('this is a user');
user === 'this is user'; // false
user === 'user'; // false
user === 'Symbol'; // false
user === true; // false
user === false; // false
user === 123; // false
user === 0; // false
user === null; // false
user === undefined; // false...
# 똑같은 설명을 붙인 심볼을 만들어도 두 값을 비교하면 false 반환
const symbolA = Symbol('this is Symbol');
const symbolB = Symbol('this is Symbol');
console.log(symbolA === symbolB); // false
# 오류 발생 예시
console.log(9007199254740991 + 1 === 9007199254740991 + 2); // true
console.log(9007199254740991 + 2); /// 9007199254740992
console.log(9007199254740993); /// 9007199254740992
# BigInt 선언 예시
console.log(9007199254740993n); // 9007199254740993n
console.log(BigInt('9007199254740993')); // 9007199254740993n
typeof 'Codeit'; // string
typeof Symbol(); // symbol
typeof {}; // object
typeof []; // object
typeof true; // boolean
typeof(false); // boolean
typeof(123); // number
typeof(NaN); // number
typeof(456n); // bigint
typeof(undefined); // undefined
# 특별히 알아둘 사항들
typeof null; // object
function sayHi() {
console.log('Hi!?');
}
typeof sayHi; // function
# 형변환 예시
const x = "3";
const y = 5;
console.log(x * y);
Boolean(평가하고자 하는 값) # True, False 중 하나로 나옴
true이면 오른쪽값 리턴, 왼쪽값이 false이면 그대로 왼쪽 리턴true이면 왼쪽값 리턴, 왼쪽값이 false이면 오른쪽 리턴# AND
console.log('Codeit' && 'Javascript');
# OR
console.log('Codeit'||'Javascript');
# 예시들
console.log(null && undefined); // null
console.log(0 || true); // true
console.log('0' && NaN); // NaN
console.log({} || 123); // {}
?? 연산자를 이용해서 null, undefined 값을 가려내는 연산자?? 연산자의 왼쪽의 값이 null이나 undefined라면 연산자 오른쪽의 값이 리턴됨?? 연산자 왼쪽의 값이 null이나 undefined가 아니라면 연산자 왼쪽의 값이 리턴됨 (OR과 비슷)var title = 'codeit'; # 기존 방식
//바뀐 방식:
let // 값의 재할당 필요
const // 값의 재할당 필요하지 않음
function sayHi() {
var userName = 'codeit';
console.log(`Hi ${userName}!`);
}
console.log(userName); // ReferenceError
for (var i = 0; i < 5; i++) {
console.log(i);
}
console.log(i); // 5
function sayHi() {
const userName = 'codeit';
console.log(`Hi ${userName}!`);
}
for (let i = 0; i < 5; i++) {
console.log(i);
}
{
let language = 'JavaScript';
}
console.log(userName); // ReferenceError
console.log(i); // ReferenceError
console.log(language); // ReferenceError
function 함수이름() { // function 키워드 사용
동작;
return 리턴값;
};
// 함수 선언
function sayHi() {
console.log('Hi!');
}
// 함수 표현식
const sayHi = function () {
console.log('Hi!');
};
예시: sayHi함수는 블록스코프를 가져서 블록 밖에서는 사용이 불가하므로 오류가 발생함. 이 때 만약 함수선언 방식으로 선언되었다면 오류가 발생하지 않는다.
# 오류가 발생함
{
let sayHi = function () {
console.log('Hi!');
};
}
sayHi();
// 변수에 할당해서 활용
const printJS = function () {
console.log('JavaScript');
};
// 객체의 메소드로 활용
const codeit = {
printTitle: function () {
console.log('Codeit');
}
}
// 콜백 함수로 활용
myBtn.addEventListener('click', function () {
console.log('button is clicked!');
});
// 고차 함수로 활용
function myFunction() {
return function () {
console.log('Hi!?');
};
};
const sayHi = function () {
console.log('Hi');
};
console.log(sayHi.name); // sayHi
const sayHi = function printHiInConsole() {
console.log('Hi');
};
console.log(sayHi.name); // printHiInConsole
# 이 이름은 외부에서 함수를 호출할 때는 사용되지 않음
const sayHi = function printHiInConsole() {
console.log('Hi');
};
printHiInConsole(); // ReferenceError
(function () {
console.log('Hi!');
})(); # 선언과 동시에 실행됨
(function (x, y) {
console.log(x + y);
})(3, 5);
# 이름을 지어주더라도 외부에서 재호출할 수는 없음
(function sayHi() {
console.log('Hi!');
})();
sayHi(); // ReferenceError
# 따라서 대부분은 이름을 짓지 않으나, 재귀호출을 구현하고자 할 때는 이름이 필요함
(function countdown(n) {
console.log(n);
if (n === 0) {
console.log('End!');
} else {
countdown(n - 1);
}
})(5);
# 코드 실행 결과가 다른 하나
const sayCodeit = function () {
console.log('Codeit');
};
sayCodeit();
const codeit = {
title: 'codeit',
printTitle: function () {
console.log('Codeit');
},
};
codeit.printTitle();
const codeit = [
function () {
console.log('Codeit');
},
];
codeit[0]();
// 여기까지 전부 같음
// 마지막 코드만 다름
function getFunction() {
return function () {
console.log('Codeit');
}
}
const printCodeit = getFunction; // getFunction()로 수정해야 같아짐
printCodeit();
function sayHi(name = 'Codeit') {
console.log(`Hi! ${name}`);
}
sayHi('JavaScript'); // Hi! JavaScript
sayHi(); // Hi! Codeit
arguments 객체arguments.length # 입력값 개수 확인
arguments[0] # 인덱싱으로 접근 가능
for (const arg of arguments){
console.log(arg);
}; # 반복문 실행
// 실습
function firstWords() {
let word = '';
// 여기에 코드를 작성하세요
arg_length = arguments.length;
for (i=0; i<arg_length; i++){
word += arguments[i][0]
}
console.log(word);
}
firstWords('나만', '없어', '고양이');
firstWords('아니', '바나나말고', '라면먹어');
firstWords('만두', '반으로', '잘라먹네', '부지런하다');
firstWords('결국', '자바스크립트가', '해피한', '지름길');
firstWords('빨간색', '주황색', '노란색', '초록색', '파란색', '남색', '보라색');
... 붙이기 → 배열이므로 배열의 메소드들(splice(시작인덱스, 끝인덱스)) 등 사용 가능function printArguments(...args) {
// args 객체의 요소들을 하나씩 출력
for (const arg of args) {
console.log(arg);
}
}
printArguments('Young', 'Mark', 'Koby');
function ignoreFirst(first_params, ...rest_params){
// console.log(rest_params)
for (i=0; i<rest_params.length; i++){
console.log(rest_params[i]);
}
}
ignoreFirst('1세대', '2세대', '3세대');
ignoreFirst('곰팡이', '강아지', '고양이');
ignoreFirst(20, 9, 18, 19, 30, 34, 40);
const sayHi = (파라미터) => { // 파라미터가 하나일 때는 소괄호 생략 가능
명령문;
};
// 화살표 함수 정의
const getTwice = (number) => {
return number * 2;
};
// 콜백 함수로 활용
myBtn.addEventListener('click', () => {
console.log('button is clicked!');
});
// 1. 함수의 파라미터가 하나 뿐일 때
const getTwice = (number) => {
return number * 2;
};
// 파라미터를 감싸는 소괄호 생략 가능
const getTwice = number => {
return number * 2;
};
// 2. 함수 동작 부분이 return문만 있을 때
const sum = (a, b) => {
return a + b;
};
// return문과 중괄호 생략 가능
const sum = (a, b) => a + b;
arguments 객체가 존재하지 않음
const user = {
firstName: 'Tess',
lastName: 'Jang',
getFullName: function () {
return `${this.firstName} ${this.lastName}`;
},
};
console.log(user.getFullName()); // getFullName 안에서의 this는 getFullName을 호출한 user객체가 담긴다!
function printThisTitle() {
console.log(this.title);
}
const courseA = {
title: '프로그래밍 기초 in JavaScript',
printTitle: printThisTitle,
};
const courseB = {
title: '컴퓨터 개론',
printTitle: courseA.printTitle,
};
const courseC = {
title: '웹 퍼블리싱',
printTitle: courseB.printTitle,
};
courseA.printTitle();
courseB.printTitle();
courseC.printTitle();
//프로그래밍 기초 in JavaScript
//컴퓨터 개론
//웹 퍼블리싱
const getFullName = () => `${this.firstName} ${this.lastName}`;
const user = {
firstName: 'Ted',
lastName: 'Chang',
getFullName: getFullName,
};
console.log(user.getFullName());
/*
getFullName에서 this는 window 객체를 가리키기 때문에 이 코드는 undefined undefined가 콘솔에 출력될 거야.
Arrow Function에서 this는 일반함수와 다르게 함수가 호출될 때 호출한 객체를 가리키지 않아.
메소드를 만들 때 그 메소드를 품은 객체를 this 로 가리키고 싶다면 Arrow Function 보다는 일반 함수를 사용하는 게 좋아.
틀린선지: Ted Chang이 출력됨
동환: this를 활용한 메소드를 객체 내부에서 선언하면 항상 그 객체를 가리키기 때문에, 만약 다른 객체의 메소드로도 활용할 거라면 객체 외부에서 전역 스코프를 가지는 함수로 선언해야 해.
this를 활용한 메소드를 다른 여러 객체에 활용한다고 해서 반드시 전역 스코프를 가지는 함수를 만들 필요는 없습니다. 일반함수로 this를 활용한 메소드를 객체 내부에서 선언하고 다른 객체에서 그 메소드를 참조하더라도 this는 항상 그 메소드를 호출한 객체를 가리키게 됩니다. (동환: X)
*/
문장(statements) vs. 표현식(expressions)
문장: 어떤 동작이 일어나도록 작성된 최소한의 코드 덩어리
표현식: 결과적으로 하나의 값이 되는 모든 코드
조건을 다루는 표현식
기존: if, switch
조건연산자(삼항연산자): 조건 ? truthy할때표현식 : falsy할때표현식 ← ?, : 이케 두개의 연산자 사용, 자바스크립트에서 세 개의 피연산자를 가지는 유일한 연산자
장점: 간단한 조건식의 경우에는 if문 보다 훨씬 더 간결하게 표현할 수 있음
단점: 내부에 변수나 함수를 선언한다거나 반복문 같은 표현식이 아닌 문장은 작성할 수 없다는 한계가 있어서 if문을 완벽하게 대체할 수는 없음
const cutOff = 80;
const passChecker = (score) => score > cutOff ? '합격입니다!' : '불합격입니다!';
console.log(passChecker(75));
const msg = speed > 50 ? '[주의!]과속주행 중입니다.' : '정속주행 중입니다.';
//if문 -> 조건연산자
// if문
let msg = '';
if (x > 3) {
msg = 'x는 3보다 크다.';
} else {
msg = 'x는 3보다 크지 않다.';
}
//조건연산자
let msg = x > 3 ? 'x는 3보다 크다.' : 'x는 3보다 크지 않다.';
...를 붙여서 실행함[1, 2, 3] → 1 2 3const webPublishing = ['HTML', 'CSS'];
const interactiveWeb = [...webPublishing, 'JavaScript'];
console.log(webPublishing);
console.log(interactiveWeb);
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const arr3 = [...arr1, ...arr2];
console.log(arr3);
const members = ['태호', '종훈', '우재'];
const newObject = { ...members };
console.log(newObject); // {0: "태호", 1: "종훈", 2: "우재"}
const topic = {
name: '모던 자바스크립트',
language: 'JavaScript',
}
const newArray = [...topic]; // TypeError!
const codeit = {
name: 'codeit',
};
const codeitClone = {
...codeit, // spread 문법!
};
console.log(codeit); // {name: "codeit"}
console.log(codeitClone); // {name: "codeit"}
const latte = {
esspresso: '30ml',
milk: '150ml'
};
const cafeMocha = {
...latte,
chocolate: '20ml',
}
console.log(latte); // {esspresso: "30ml", milk: "150ml"}
console.log(cafeMocha); // {esspresso: "30ml", milk: "150ml", chocolate: "20ml"}
const latte = {
esspresso: '30ml',
milk: '150ml'
};
const cafeMocha = {
...latte,
chocolate: '20ml',
}
[...latte]; // Error
(function (...args) {
for (const arg of args) {
console.log(arg);
}
})(...cafeMocha); // Error
const snacks = ['원카칩', '꿀버터칩', '헛스윙칩', '태양칩', '야채시간'];
const drinks = ['사이다', '콜라', '우유', '물', '커피', '레몬에이드'];
function printArguments(...args) {
for (const arg of args) {
console.log(arg);
}
}
// 1. Spread 구문을 활용해서 snacks와 drinks 배열을 각각 mySnacks와 myDrinks 변수에 복사해 주세요
const mySnacks = [...snacks]
const myDrinks = [...drinks]
mySnacks.splice(2, 3);
myDrinks.splice(1);
// 2. Spread 구문을 활용해서 mySnacks와 myDrinks 순서로 두 배열을 합쳐서 myChoice 변수에 할당해 주세요
const myChoice = [...mySnacks, ...myDrinks]
// 3. Spread 구문을 활용해서 myChoice의 각 요소들을 printArguments 함수의 아규먼트로 전달해 주세요
printArguments(...myChoice);
// 프로퍼티 네임과 변수나 함수 이름이 같아서 축약
function sayHi() {
console.log('Hi!');
}
const title = 'codeit';
const birth = 2017;
const job = '프로그래밍 강사';
const user = {
title,
birth,
job,
sayHi,
};
console.log(user); // {title: "codeit", birth: 2017, job: "프로그래밍 강사", sayHi: ƒ}
// 메소드에서 function 키워드 생략
const user = {
firstName: 'Tess',
lastName: 'Jang',
getFullName() {
return `${this.firstName} ${this.lastName}`;
},
};
console.log(user.getFullName()); // Tess Jang
['hi' + '이름변수']:값 이런식의 표현도 가능const propertyName = 'birth';
const getJob = () => 'job';
const codeit = {
['topic' + 'Name']: 'Modern JavaScript',
[propertyName]: 2017,
[getJob()]: '프로그래밍 강사',
};
// 접근법
codeit.topicName;
codeit[propertyName];
codeit[getJob()];
codeit.job;
codeit.birth;
// Array Destructuring
const members = ['코딩하는효준', '글쓰는유나', '편집하는민환'];
const [macbook, ipad, coupon] = members;
console.log(macbook); // 코딩하는효준
console.log(ipad); // 글쓰는유나
console.log(coupon); // 편집하는민환
// Object Destructuring
const macbookPro = {
title: '맥북 프로 16형',
price: 3690000,
};
const { title, price } = macbookPro;
console.log(title); // 맥북 프로 16형
console.log(price); // 3690000
// Array Destructuring: 기본값, rest 문법 활용
const members = ['코딩하는효준', '글쓰는유나', undefined, '편집하는민환', '촬영하는재하'];
const [macbook, ipad, airpod = '녹음하는규식', ...coupon] = members;
console.log(macbook); // 코딩하는효준
console.log(ipad); // 글쓰는유나
console.log(airpod); // 녹음하는규식
console.log(coupon); // (2) ["편집하는민환", "촬영하는재하"]
// Object Destructuring
const macbookPro = {
title: '맥북 프로 16형',
price: 3690000,
memory: '16 GB 2667 MHz DDR4',
storage: '1TB SSD 저장 장치',
};
const { title, price, color = 'silver', ...rest } = macbookPro;
console.log(title); // 맥북 프로 16형
console.log(price); // 3690000
console.log(color); // silver
console.log(rest); // {memory: "16 GB 2667 MHz DDR4", storage: "1TB SSD 저장 장치"}
printCatName과 같이 중첩된 객체의 프로퍼티를 다룰 때는 user.cat.name에 접근하기 전에 user.cat이 null 혹은 undefined가 아니라는 것을 검증하고 접근해야 에러를 방지할 수 있음 function printCatName(user) {
console.log(user.cat.name);
}
const user1 = {
name: 'Captain',
cat: {
name: 'Crew',
breed: 'British Shorthair',
}
}
printCatName(user1); // Crew
// 검증방법1: and 연산자
function printCatName(user) {
console.log(user.cat && user.cat.name);
}
// 검증방법2: 옵셔널 체이닝
function printCatName(user) {
console.log(user.cat?.name);
}
/*만약 옵셔널 체이닝 연산자 왼편의 프로퍼티 값이
undefined 또는 null이 아니라면 그 다음 프로퍼티 값을 리턴하고
그렇지 않은 경우에는 undefined를 반환*/
// 같은 연산을 삼항연산자를 통해 구현
function printCatName(user) {
console.log((user.cat === null || user.cat === undefined) ? undefined : user.cat.name);
}
//응용
function printCatName(user) {
console.log(user.cat?.name ?? '함께 지내는 고양이가 없습니다.');
}
const user2 = {
name: 'Young',
}
printCatName(user2); // 함께 지내는 고양이가 없습니다.
// 1. Destructuring 문법을 활용해서 numbers 배열의 각 요소를 one, two, three라는 변수에 할당해보세요
const numbers = [1, 2, 3];
const [one, two, three] = numbers;
// 2. Destructuring 문법을 활용해서 TV는 livingRoom, 나머지 요소들(배열)은 kitchen 변수에 할당해 주세요
const products = ['TV', '식탁', '냉장고', '전기밥솥', '전자레인지', '오븐', '식기세척기'];
const [livingRoom, ...kitchen] = products;
// 3. Destructuring 문법을 활용해서 두 변수의 값을 서로 바꿔주세요
let firstName = 'Kang';
let lastName = 'Young';
[firstName, lastName] = [lastName, firstName];
// 테스트 코드
console.log(one);
console.log(two);
console.log(three);
console.log(livingRoom);
console.log(kitchen[1]);
console.log(firstName);
console.log(lastName);
객체:
// 1. Destructuring 문법을 사용해서 title, artist, year, medium 변수에 myBestArt 객체의 각 프로퍼티를 할당해 주세요
const myBestArt = {
title: '별이 빛나는 밤에',
artist: '빈센트 반 고흐',
year: 1889,
medium: '유화',
};
const {title, artist, year, medium} = myBestArt;
// 2. Destructuring 문법을 활용해서 myBestSong의 프로퍼티 중 title과 artist는 각각 songName과 singer라는 변수에, 나머지는 rest라는 변수에 객체로 할당해 주세요
const myBestSong = {
title: '무릎',
artist: '아이유(IU)',
release: '2015.10.23.',
lyrics: '모두 잠드는 밤에...'
};
// const {songName, singer, ...rest} = myBestSong;
const {title: songName, artist: singer, ...rest} = myBestSong;
// 3. printMenu 함수 안에 잘못 작성된 Destructuring 코드를 수정해 주세요
const menu1 = { name: '아메리카노' };
const menu2 = { name: '바닐라 라떼', ice: true };
const menu3 = { name: '카페 모카', ice: false };
function printMenu(menu) {
// menu 파라미터로 전달되는 객체에 ice 프로퍼티가 없을 경우 기본값은 true여야 합니다
const {name, ice = true} = menu;
console.log(`주문하신 메뉴는 '${ice ? '아이스' : '따뜻한'} ${name}'입니다.`);
}
const numbers = [5, undefined, null, 3, 1, 7, 0];
const [a, b = 4, c = 2, ...d] = numbers;
console.log(a); // 5
console.log(b); // 4
console.log(c); // null
console.log(d[2]); // 7
console.log(d[4]); // undefined
// 아래 코드들이 정상적으로 동작하려면 printFavoritSong 함수를 어떻게 선언해야 할까요?
function printFavoritSong(name, music){
console.log(`최근 '${name}'님이 즐겨듣는 노래는 '${music.singer}'의 '${music.title}'이라는 노래입니다.`);
};
/* alternative functions:
function printFavoritSong(name, music) {
const { singer, title } = music;
console.log(`최근 '${name}'님이 즐겨듣는 노래는 '${singer}'의 '${title}'이라는 노래입니다.`);
}
function printFavoritSong(name, { title, singer }) {
console.log(`최근 '${name}'님이 즐겨듣는 노래는 '${singer}'의 '${title}'이라는 노래입니다.`);
}
*/
const music1 = { title: '난치병', singer: '하림' };
const music2 = { title: '너의 모든 순간', singer: '성시경' };
const music3 = { title: '무릎', singer: '아이유' };
const music4 = { title: '옛사랑', singer: '이문세' };
const music5 = { title: '한숨', singer: '이하이' };
const music6 = { title: '추억의 책장을 넘기면', singer: '이선희' };
printFavoritSong('영훈', music4);
printFavoritSong('동욱', music1);
printFavoritSong('대위', music3);
printFavoritSong('소원', music2);
printFavoritSong('우재', music5);
printFavoritSong('영준', music6);

// 에러 객체 직접 만드는 코드
throw new TypeError('타입 에러가 발생했습니다.');
try{
코드; // 오류 발생 시점 이후의 코드는 실행되지 않음
}catch(error){ // error 대신 err, e 등 자유롭게 작명 가능
코드; // 오류 발생 후 실행되는 코드
console.log(error.name); // 콘솔창에 출력하기
console.log(error.message);
console.error(error) // 진짜 에러 메세지처럼 빨간색으로 출력
}
try {
// 실행할 코드
} catch (err) {
// 에러가 발생했을 때 실행할 코드
} finally {
// 에러 발생 여부와 무관하게 항상 실행할 코드
}
// 기본 유니코드 방식 정렬
const letters = ['D', 'C', 'E', 'B', 'A'];
const numbers = [1, 10, 4, 21, 36000];
letters.sort();
numbers.sort();
console.log(letters); // (5) ["A", "B", "C", "D", "E"]
console.log(numbers); // (5) [1, 10, 21, 36000, 4]
// 다른 정렬 정의하기
const numbers = [1, 10, 4, 21, 36000];
// 오름차순 정렬
numbers.sort((a, b) => a - b);
console.log(numbers); // (5) [1, 4, 10, 21, 36000]
// 내림차순 정렬
numbers.sort((a, b) => b - a);
console.log(numbers); // (5) [36000, 21, 10, 4, 1]
const letters = ['a', 'c', 'b'];
const numbers = [421, 721, 353];
letters.reverse();
numbers.reverse();
console.log(letters); // (3) ["b", "c", "a"]
console.log(numbers); // (3) [353, 721, 421]
map & set
객체는 property name을 통해 이름이 있는 여러 값들을 묶을 때 활용할 수 있고, 배열은 index를 통해 순서가 있는 여러 값들을 묶을 때 유용하게 활용할 수 있음
→ ES2015에서 객체와 비슷한 Map과 배열과 비슷한 Set이라는 데이터 구조가 새롭게 등장
Map
객체와 비슷한 점: 이름이 있는 데이터를 저장
객체와 다른 점:
map.set(key, value): key를 이용해 value를 추가하는 메소드.map.get(key): key에 해당하는 값을 얻는 메소드. key가 존재하지 않으면 undefined를 반환.map.has(key): key가 존재하면 true, 존재하지 않으면 false를 반환하는 메소드.map.delete(key): key에 해당하는 값을 삭제하는 메소드.map.clear(): Map 안의 모든 요소를 제거하는 메소드.map.size: 요소의 개수를 반환하는 프로퍼티. (메소드가 아닌 점 주의! 배열의 length 프로퍼티와 같은 역할)// Map 생성: new 키워드
const codeit = new Map();
// set 메소드
codeit.set('title', '문자열 key');
codeit.set(2017, '숫자형 key');
codeit.set(true, '불린형 key');
// get 메소드
console.log(codeit.get(2017)); // 숫자형 key
console.log(codeit.get(true)); // 불린형 key
console.log(codeit.get('title')); // 문자열 key
// has 메소드
console.log(codeit.has('title')); // true
console.log(codeit.has('name')); // false
// size 프로퍼티
console.log(codeit.size); // 3
// delete 메소드
codeit.delete(true);
console.log(codeit.get(true)); // undefined
console.log(codeit.size); // 2
// clear 메소드
codeit.clear();
console.log(codeit.get(2017)); // undefined
console.log(codeit.size); // 0
set.add(value): 값을 추가하는 메소드. (메소드를 호출한 자리에는 추가된 값을 가진 Set 자신을 반환.)
set.has(value): Set 안에 값이 존재하면 true, 아니면 false를 반환하는 메소드.
set.delete(value): 값을 제거하는 메소드. (메소드를 호출한 자리에는 셋 내에 값이 있어서 제거에 성공하면 true, 아니면 false를 반환.)
set.clear(): Set 안의 모든 요소를 제거하는 메소드.
set.size: 요소의 개수를 반환하는 프로퍼티. (메소드가 아닌 점 주의! 배열의 length 프로퍼티와 같은 역할)
// Set 생성
const members = new Set();
// add 메소드
members.add('영훈'); // Set(1) {"영훈"}
members.add('윤수'); // Set(2) {"영훈", "윤수"}
members.add('동욱'); // Set(3) {"영훈", "윤수", "동욱"}
members.add('태호'); // Set(4) {"영훈", "윤수", "동욱", "태호"}
// has 메소드
console.log(members.has('동욱')); // true
console.log(members.has('현승')); // false
// size 프로퍼티
console.log(members.size); // 4
// delete 메소드
members.delete('종훈'); // false
console.log(members.size); // 4
members.delete('태호'); // true
console.log(members.size); // 3
// clear 메소드
members.clear();
console.log(members.size); // 0
/* 개별값 접근 불가*/
const members = new Set();
// add 메소드
members.add('영훈'); // Set(1) {"영훈"}
members.add('윤수'); // Set(2) {"영훈", "윤수"}
members.add('동욱'); // Set(3) {"영훈", "윤수", "동욱"}
members.add('태호'); // Set(4) {"영훈", "윤수", "동욱", "태호"}
for (const member of members) {
console.log(member); // 영훈, 윤수, 동욱, 태호가 순서대로 한 줄 씩 콘솔에 출력됨.
}
/* 중복 제거*/
const numbers = [1, 3, 4, 3, 3, 3, 2, 1, 1, 1, 5, 5, 3, 2, 1, 4];
const uniqNumbers = new Set(numbers);
console.log(uniqNumbers); // Set(5) {1, 3, 4, 2, 5}
const numbers = [1, 2, 3];
numbers.forEach((element, index, array) => {
console.log(element); // 순서대로 콘솔에 1, 2, 3이 한 줄씩 출력됨.
});
forEach 메소드 등을 사용할 때 배열의 길이를 증가시켜도 실행횟수에는 차이가 없지만 배열의 길이를 감소시키면 횟수가 줄어듦
map 메소드
forEach와 비슷하게 배열의 요소를 하나씩 살펴보면서 반복 작업을 하는 메소드
첫 번째 아규먼트로 전달하는 콜백 함수가 매번 리턴하는 값들을 모아서 새로운 배열을 만들어 리턴하는 특징이 있습니다.
const numbers = [1, 2, 3];
const twiceNumbers = numbers.map((element, index, array) => {
return element * 2;
});
console.log(twiceNumbers); // (3) [2, 4, 6]
const 새로생성할_배열이름 = 필터링할_배열.filter((el) => el.배열의키값 == “apple”)
const devices = [
{name: 'GalaxyNote', brand: 'Samsung'},
{name: 'MacbookPro', brand: 'Apple'},
{name: 'Gram', brand: 'LG'},
{name: 'SurfacePro', brand: 'Microsoft'},
{name: 'ZenBook', brand: 'Asus'},
{name: 'MacbookAir', brand: 'Apple'},
];
const apples = devices.filter((element, index, array) => {
return element.brand === 'Apple';
});
console.log(apples); // (2) [{name: "MacbookPro", brand: "Apple"}, {name: "MacbookAir", brand: "Apple"}]
const devices = [
{name: 'GalaxyNote', brand: 'Samsung'},
{name: 'MacbookPro', brand: 'Apple'},
{name: 'Gram', brand: 'LG'},
{name: 'SurfacePro', brand: 'Microsoft'},
{name: 'ZenBook', brand: 'Asus'},
{name: 'MacbookAir', brand: 'Apple'},
];
const myLaptop = devices.find((element, index, array) => {
console.log(index); // 콘솔에는 0, 1, 2까지만 출력됨.
return element.name === 'Gram';
});
console.log(myLaptop); // {name: "Gram", brand: "LG"}
const numbers = [1, 3, 5, 7, 9];
// some: 조건을 만족하는 요소가 1개 이상 있는지
const someReturn = numbers.some((element, index, array) => {
console.log(index); // 콘솔에는 0, 1, 2, 3까지만 출력됨.
return element > 5;
});
console.log(someReturn); // true;
const numbers = [1, 3, 5, 7, 9];
// every: 조건을 만족하지 않는 요소가 1개 이상 있는지
const everyReturn = numbers.every((element, index, array) => {
console.log(index); // 콘솔에는 0까지만 출력됨.
return element > 5;
});
console.log(everyReturn); // false;
const numbers = [1, 2, 3, 4];
// reduce
const sumAll = numbers.reduce((accumulator, element, index, array) => {
return accumulator + element;
}, 0);
console.log(sumAll); // 10
태순이를 도와서 HTML DOM 메소드와 forEach 메소드를 통해 data 변수에 담긴 할 일들을 화면에 띄워보세요.
단, 아래의 조건들을 잘 지켜주셔야 합니다.
forEach 메소드를 활용해주세요.
할 일들은 li태그로 만들어 주세요.
할 일들은 기본적으로 item 이라는 클래스를 가지고 있어야 합니다.
할 일 중에서 isClear 프로퍼티가 true인 할 일은 done 이라는 클래스도 추가해 주세요.
할 일들에 1부터 시작하는 번호를 매겨주세요. (ex) 1. 게임하기 2. 쇼핑하기 3. ...)
할 일들은 <ul class="list"></ul>태그 안에 넣어주세요.
const list = document.querySelector('.list');
const data = [{
title: '자바스크립트 공부하기',
isClear: true,
}, {
title: '쓰레기 분리수거',
isClear: false,
}, {
title: '고양이 밥주기',
isClear: true,
}, {
title: '독서하기',
isClear: false,
}, {
title: '영어 공부하기',
isClear: false,
}
];
// 여기에 코드를 작성해 주세요.
data.forEach((todo, i) => { // 1번 조건
const li = document.createElement('li'); // 2번 조건
if (todo.isClear) {
li.classList.add('item', 'done'); // 4번 조건
} else {
li.classList.add('item'); // 3번 조건
}
li.textContent = `${i + 1}. ${todo.title}`; // 5번 조건
list.appendChild(li); // 6번 조건
});
['YUMMY', 'COUNT', 'ABUSE', 'SOUND', 'SWING']
평소 추리 소설을 좋아하는 종훈이는 잠깐의 고민으로 이 속에 YOUNG (강영훈의 닉네임)이 숨겨져 있다는 걸 찾아냈는데요.
템플릿에 주어진 배열의 map 메소드를 활용해서 'Y', 'O', 'U', 'N', 'G'을 추출한 새로운 배열을 answer 변수에 담아주세요.
const quiz = ['YUMMY', 'COUNT', 'ABUSE', 'SOUND', 'SWING'];
// 여기에 코드를 작성하세요
const answer = quiz.map((element, index) => {
return element[index];
});
// 테스트 코드
console.log(answer);
const seoul = ['김영훈', '김윤수', '김동욱', '강대위', '김영준',
'김규식', '김태호', '김효신', '손효준', '김현승', '김재하', '김유나',
'김재훈', '김혜선', '김민환', '김규리', '김소원', '김우재', '최영준',
'김태순', '김종훈', '김성환', '김승용', '김지혜', '이승욱', '김도현',
'김승규', '윤하은', '김유진', '김정민', '김혜정', '김예진', '김여진',
'김성희', '김혜수', '김인선', '김상필', '김혜진', '서상원', '김상혜',
'김민기', '김그루', '김희지'];
// 여기에 코드를 작성해 주세요.
const notKims = seoul.filter((element, index) => {
return element[0] != '김';
})
// 테스트 코드
console.log(notKims);
find 메소드를 활용해서 입력받은 유저 이름과 전화번호가 일치하는 객체를 찾아 user 변수에 할당해 주세요!
findEmail 함수가 제대로 완성된다면, 각 input 태그에 적절한 값을 입력했을 때 해당하는 이메일을 잘 찾아줄 겁니다!
const nameInput = document.querySelector('#user-name');
const phoneInput = document.querySelector('#phone-number');
const findBtn = document.querySelector('#find');
const data = [
{ userName: '막대기', phoneNumber: '01012341111', email: 'stick@go_do_it.kr' },
{ userName: 'young', phoneNumber: '01012342222', email: 'kang@go_do_it.kr' },
{ userName: '코린이', phoneNumber: '01012343333', email: 'corin2@go_do_it.kr' },
{ userName: 'captain', phoneNumber: '01012344444', email: 'crew@go_do_it.kr' },
{ userName: 'YH', phoneNumber: '01012345555', email: 'whyH@go_do_it.kr' },
{ userName: '망고쥬스', phoneNumber: '01012346666', email: 'drinkMango@go_do_it.kr' },
{ userName: 'nemoming', phoneNumber: '01012347777', email: 'ractAngle@go_do_it.kr' },
{ userName: '강그루', phoneNumber: '01012348888', email: 'riverTree@go_do_it.kr' },
{ userName: '개룩발룩', phoneNumber: '01012349999', email: 'checkShirts@go_do_it.kr' },
{ userName: '오렌지쥬스', phoneNumber: '01012341010', email: 'delmonte@go_do_it.kr' },
];
function findEmail() {
const nameValue = nameInput.value;
const phoneValue = phoneInput.value;
// 여기에 코드를 작성하세요
const user = data.find((element, index) => {
if ((element.phoneNumber == phoneValue)&&(element.userName == nameValue)){
return element.email;
}
});
const message = user
? `${user.userName}님의 이메일은 ${user.email} 입니다.`
: '이메일을 찾을 수 없습니다. 입력 정보를 다시 확인해 주세요.';
alert(message);
}
findBtn.addEventListener('click', findEmail);
아래의 조건을 참고하여 각 팀의 멤버들 중에 순수 스파이가 아닌 사람이 있는지 확인하는 checkSpy 함수를 완성해 주세요.
스파잇의 직원들은 모두 '스파이'로 불리고, 이중 스파이는 '스파이와 비슷한 이름'을 갖고 있습니다.
checkSpy 함수의 첫번째 파라미터에는 하나의 팀을 표현하는 객체를 아규먼트로 전달받게 됩니다.
checkSpy 함수는 내부에서 some 혹은 every 메소드를 활용합니다.
checkSpy 함수는 최종적으로 message 변수에 담긴 값을 출력하게 됩니다.
아래 출력 결과를 참고하여 message 변수를 선언하고, 각 팀의 멤버들을 확인한 뒤 적절한 문구를 담아 주세요!
const spait = [
{ codeName: 'ApplePie', members: ['스파이', '스파이', '스파이', '스파이', '스파이'] },
{ codeName: 'BigBoss', members: ['스파이', '스파이', '스과이', '스파이', '스파이'] },
{ codeName: 'CEO', members: ['스파이', '스파이', '스파이', '습하이', '스파이'] },
{ codeName: 'DeathNote', members: ['스파이', '스파이', '스파이', '스파이', '스파이'] },
{ codeName: 'EarlyBird', members: ['스파이', '스마이', '스파이', '스파이', '스파이'] },
{ codeName: 'Faker', members: ['스파이', '스파이', '스파이', '스파이', '스파이'] },
];
function checkSpy(team) {
// 여기에 코드를 작성하세요
const everyReturn = team.members.every((element, index) => {
return element == '스파이';
});
//console.log(everyReturn);
if (everyReturn == true){
message = `팀 ${team.codeName} 에는 이중 스파이가 없습니다.`
} else {
message = `[주의!] 팀 ${team.codeName} 에 이중 스파이가 있습니다!`
}
console.log(message);
}
// 테스트 코드
spait.forEach((team) => checkSpy(team));
const data = [
{ company: 'Naber', month: 3 },
{ company: 'Amajohn', month: 12 },
{ company: 'Coogle', month: 10 },
{ company: 'Ittel', month: 6 },
{ company: 'Sasung', month: 4 },
{ company: 'CaCao', month: 3 },
{ company: 'Microhard', month: 17 },
];
// 여기에 코드를 작성하세요
const totalCareer = data.reduce((accum, element) => {
return accum + element.month;
}, 0);
console.log(`상원이의 경력은 총 ${totalCareer}개월입니다.`);
모듈이란? 공통된 기능에 따라 하나의 프로그램을 여러개의 파일로 모듈화한 하나의 파일
코드를 좀 더 효율적으로 관리할 수 있고,비슷한 기능이 필요할 때 다른 프로그램에서 재사용 할 수도 있다는 장점이 있습니다.
모듈 파일의 조건
<body>
<script type="module" src="index.js"></script>
</body>
// export
export function addMenu(data) {
// 함수 body
};
// import
import {addMenu} from './add.js';
import {title as printerTitle, print } from './printer.js'; // as 키워드로 이름 변경
// printer.js
export const title = 'CodeitPrinter';
export function print(value) {
console.log(value);
};
// change name
import { title as printerTitle, print, printArr } from './printer.js';
import { title, data as members } from './members.js';
printer(title);
arrPrinter(members);
// all at once
import * as printerJS from './printer.js';
console.log(printerJS.title); // CodeitPrinter
console.log(printerJS.print); // ƒ print(value) { console.log(value); }
// default
import { default as printerJS } from './printer.js';
console.log(printerJS.title); // CodeitPrinter
console.log(printerJS.print); // ƒ print(value) { console.log(value); }
// orr
import printerJS from './printer.js';
console.log(printerJS.title); // CodeitPrinter
console.log(printerJS.print); // ƒ print(value) { console.log(value); }
// export: index.js
import { title, print } from './printer.js';
print(title);
// all at once
const title = 'CodeitPrinter';
function print(value) {
console.log(value);
}
function printArr(arr) {
arr.forEach((el, i) => {
console.log(`${i + 1}. ${el}`);
});
}
export { title as printerTitle, print, printArr };
// default
const title = 'CodeitPrinter';
function print(value) {
console.log(value);
}
export default print;
export하는 모든 대상을 import하는 방법: import * as printerJS from './printer.js'
*는 와일드카드 문자라고 불림
한번에 export하기: export {minji as mini}, export {minji, zuzana}
default export
export default 'codeit'; 등 하나의 대상만을 export함.
import codeit으로 import 가능
default는 한 모듈파일 안에서 한번만 붙일 수 있음
const user = {
email: 'minzikx@gmail.com', // 프로퍼티들
birthdate: '20030419',
buy(item) { // 메소드
console.log(`${this.email} buys ${item.name}`);
}, // this는 현재 속해있는 전체 객체 (즉, user)를 나타냄
}
function createUser(email, birthdate) {
const user = {
email,
birthdate,
buy(item) {
console.log(`${this.email} buys ${item.name}`);
},
};
return user;
}
const user1 = createUser('chris123@google.com', '19920321');
const user2 = createUser('jerry99@google.com', '19950719');
const user3 = createUser('alice@google.com', '19931224');
new를 붙여서 호출해야 함function User(email, birthdate) {
this.email = email;
this.birthdate = birthdate;
this.buy = function (item) {
console.log(`${this.email} buys ${item.name}`);
};
}
const user1 = new User('chris123@google.com', '1992-03-21');
const user2 = new User('jerry99@google.com', '1995-07-19');
const user3 = new User('alice@google.com', '1993-12-24');
class User {
constructor(email, birthdate) {
this.email = email;
this.birthdate = birthdate;
}
buy(item) {
console.log(`${this.email} buys ${item.name}`);
}
}
const user1 = new User('chris123@google.com', '1992-03-21');
const user2 = new User('jerry99@google.com', '1995-07-19');
const user3 = new User('alice@google.com', '1993-12-24');
예제
class Car {
constructor(color, speed) {
this.color = color;
this.speed = speed;
}
run() {
console.log(`Runs at ${this.speed}`);
}
}
const car1 = new Car('blue', '100km/h');
car1.run();
class BankAccount {
constructor(name, money) {
this.holder = name;
this.balance = money;
}
deposit(money) {
this.balance += money;
}
withdraw(money) {
if (this.balance - money < 0) {
console.log('Insufficient balance');
} else {
this.balance -= money;
}
}
transfer(money, anotherAccount) {
const account = anotherAccount;
if (this.balance - money < 0) {
console.log('Insufficient balance');
} else {
this.balance -= money;
account.balance += money;
}
}
}
class User {
constructor(email, birthdate) {
// 사용자의 이메일 주소
this.email = email;
// 사용자의 생일
this.birthdate = birthdate;
}
// 물건 구매하기
buy(item) {
console.log(`${this.email} buys ${item.name}`);
}
}
_email 프로퍼티에 직접 접근하지 말고 email이라는 getter/setter 메소드로만 접근해야 함. class User {
constructor(email, birthdate) {
this.email = email;
this.birthdate = birthdate;
}
buy(item) {
console.log(`${this.email} buys ${item.name}`);
}
get email() {
return this._email;
}
set email(address) {
if (address.includes('@')) {
this._email = address;
} else {
throw new Error('invalid email address');
}
}
}
const user1 = new User('chris123@google.com', '1992-03-21');
user1.email = 'newChris123@google.com';
console.log(user1.email);
그러나 위의 코드조차 완벽히 캡슐화가 된 상태는 아님
보호하려는 프로퍼티 _email에 아래와 같이 접근이 가능하기 때문
console.log(user1._email);
user1._email = 'chris robert';
사실 자바스크립트에는 캡슐화를 자체적으로 지원하는 문법이 아직 없음(Java는 private이라는 키워드가 있어서 언어의 문법 차원에서 캡슐화를 지원)
function createUser(email, birthdate) { // Factory function
let _email = email;
const user = {
birthdate,
get email() {
return _email;
},
set email(address) {
if (address.includes('@')) {
_email = address;
} else {
throw new Error('invalid email address');
}
},
};
return user;
}
const user1 = createUser('chris123@google.com', '19920321');
console.log(user1.email);
지금 마지막 부분에서 createUser라는 Factory function으로 user1이라는 객체를 생성하고, user1 객체의 email getter 메소드를 호출했는데요. 이 코드의 실행 결과를 확인해보면, _email 변수의 값이 잘 출력됩니다. 함수 안의 변수의 값을 이미 리턴된 객체에서 읽은 건데요. 어떻게 이게 가능한 걸까요? 이것은 자바스크립트의 클로저(Closure)라고 하는 것 덕분에 가능합니다.
클로저: 자바스크립트에서 어떤 함수와 그 함수가 참조할 수 있는 값들로 이루어진 환경을 하나로 묶은 것
예를 들어, 지금 createUser 함수가 실행되는 시점에 email이라는 getter/setter 메소드는 _email 이라는 변수의 값에 접근할 수 있는 상태이고, email getter/setter 메소드들은 메소드를 갖고 있는 객체가 리턴된 이후더라도 여전히 _email에 접근하는 것이 가능하다
바로 이렇게 함수가 정의된 당시에 참조할 수 있었던 변수들을 계속 참조할 수 있는 상태의 함수를 클로저라고 한다
function createUser(email, birthdate) {
const _email = email;
let _point = 0;
function increasePoint() {
_point += 1;
}
const user = {
birthdate,
get email() {
return _email;
},
get point() {
return _point;
},
buy(item) {
console.log(`${this.email} buys ${item.name}`);
increasePoint();
},
};
return user;
}
const item = {
name: '스웨터',
price: 30000,
};
const user1 = createUser('chris123@google.com', '19920321');
user1.buy(item);
user1.buy(item);
user1.buy(item);
console.log(user1.point);
class PremiumUser extends User {class PremiumUser extends User {
constructor(email, birthdate, level) {
super(email, birthdate); // 부모클래스의 생성자들 호출!
this.level = level;
}
};
class User {
constructor(email, birthdate) {
this.email = email;
this.birthdate = birthdate;
}
buy(item) {
console.log(`${this.email} buys ${item.name}`);
}
}
class PremiumUser extends User {
constructor(email, birthdate, level) {
super(email, birthdate);
this.level = level;
}
streamMusicForFree() {
console.log(`Free music streaming for ${this.email}`);
}
}
class User {
constructor(email, birthdate) {
this.email = email;
this.birthdate = birthdate;
}
buy(item) {
console.log(`${this.email} buys ${item.name}`);
}
}
class PremiumUser extends User {
constructor(email, birthdate, level) {
super(email, birthdate);
this.level = level;
}
buy(item) {
console.log(`${this.email} buys ${item.name} with a 5% discount`);
}
streamMusicForFree() {
console.log(`Free music streaming for ${this.email}`);
}
}
const item = {
name: '스웨터',
price: 30000,
};
const user1 = new User('chris123@google.com', '19920321');
const user2 = new User('rachel@google.com', '19880516');
const user3 = new User('brian@google.com', '20051125');
const pUser1 = new PremiumUser('niceguy@google.com', '19891207', 3);
const pUser2 = new PremiumUser('helloMike@google.com', '19900915', 2);
const pUser3 = new PremiumUser('aliceKim@google.com', '20010722', 5);
const users = [user1, pUser1, user2, pUser2, user3, pUser3];
users.forEach((user) => {
user.buy(item);
});
class BankAccount {
constructor(name, money) {
this.holder = name;
this.balance = money;
}
get balance() {
return this._balance;
}
set balance(money) {
if (money >= 0) {
this._balance = money;
} else {
console.log('Not valid');
}
}
deposit(money) {
this.balance += money;
}
withdraw(money) {
if (this.balance - money < 0) {
console.log('Insufficient balance');
} else {
this.balance -= money;
}
}
transfer(money, anotherAccount) {
const account = anotherAccount;
if (this.balance - money < 0) {
console.log('Insufficient balance');
} else {
this.balance -= money;
account.balance += money;
}
}
}
class SavingsAccount extends BankAccount {
constructor(name, money){
super(name, money);
this.years = 0;
}
addInterest(rate) {
this.balance *= (1 + (rate * this.years));
}
transfer(money, anotherAccount) {
super.transfer(money, anotherAccount);
this.balance -= money * 0.005;
}
}
class DonationAccount extends BankAccount {
constructor(name, money, rate) {
super(name, money);
this.rate = rate;
}
donate(rate) {
this.balance *= (1 - this.rate);
}
transfer(money, anotherAccount) {
super.transfer(money, anotherAccount);
this.balance -= money * 0.002;
}
}
const ba1 = new BankAccount('Tom', 20000000);
const sa1 = new SavingsAccount('Jerry', 10000000);
const da1 = new DonationAccount('Kate', 30000000);
const sa2 = new SavingsAccount('Alice', 9000000);
const accountForVacation = new BankAccount('Vacation', 0);
const accounts = [ba1, sa1, da1, sa2];
for(account of accounts) {
account.transfer(800000, accountForVacation);
}
console.log(ba1.balance);
console.log(sa1.balance);
console.log(da1.balance);
console.log(sa2.balance);
console.log(accountForVacation.balance);
instanceof :
[A 클래스로 만든 객체] instanceof [A 클래스]를 하면 true가 리턴된다.
[자식 클래스로 만든 객체] instanceof [부모 클래스]를 하면 false가 리턴된다
→ 어느 클래스가 생성한 객체인지 확인 가능 (이 때, 자식클래스로 만든 객체는 부모클래스로 만든 객체로도 인정됨)
static 프로퍼티, static 메소드: 클래스에 직접적으로 딸려있는 프로퍼티와 메소드 (객체가 아닌 클래스로 접근!)
예: date, math 등
예제와는 달리 실무에서는 각 클래스를 개별파일에 하나씩 작성하는 것이 더 보편적임
fetch 함수
call-back 함수: 서버의 리스폰스가 오는 등 나중에 어떤 조건이 만족되었을 때 실행되는 함수, then메소드 사용, 프로미스 객체 생성
response 객체
fetch('https://www.google.com')
.then((response) => response.text())
.then((result) => { console.log(result); });
fetch 함수의 실행 원리: fetch 함수는 Promise 객체를 리턴함
이 객체의 then 메소드로, '리스폰스가 왔을 때 실행할 콜백'을 등록할 수 있음
이렇게 등록된 콜백들은 then 메소드로 등록한 순서대로 실행되고, 이때 이전 콜백의 리턴값을 이후 콜백이 넘겨받아서 사용이 가능함
개발자 도구
구글 제공 공식 설명 링크: https://developers.google.com/web/tools/chrome-devtools
개발자도구 실행 단축키: Ctrl 키 + Shift 키 + 알파벳 i 키
URL(Uniform Resource Locator)

HTTP

// member 객체 생성
const member = {
name: 'Michael Kim',
height: 180,
weight: 70,
hobbies: ['Basketball', 'Listening to music']
};
자바스크립트에는 객체를 생성할 수 있는 여러 가지 방법이 있는데요. 그중 한 가지는 이런 식으로 중괄호('{ }') 안에 객체의 프로퍼티의 이름(키)과 값(밸류)쌍을 순서대로 나열해서 생성하는 방법입니다. 지금 보이는 표기를 Object Literal이라고 하는데요. Object Literal을 쓸 때는 문법에 약간의 유연함이 있습니다. 저는 지금 member 객체의 각 프로퍼티의 이름인 name, height, weight, hobbies에 큰따옴표를 붙이지 않았는데요. Object Literal에서는 이렇게 프로퍼티의 이름에 큰따옴표를 붙이지 않아도 되고,
const member = {
"name": 'Michael Kim',
"height": 180,
"weight": 70,
"hobbies": ['Basketball', 'Listening to music']
};
이렇게 큰따옴표를 붙여도 됩니다.
하지만 JSON의 경우에는 프로퍼티의 이름에 반드시 큰따옴표를 붙여줘야만 합니다.
{
"name":"Michael Kim",
"height":180,
"weight":70,
"hobbies":["Basketball", "Listening to music"]
}
지금 각 프로퍼티의 이름이 모두 큰따옴표로 둘러싸여 있죠? 이렇게 JSON에서는 각 프로퍼티의 이름을 반드시 큰따옴표로 감싸주어야 합니다. 큰따옴표로 감싸주지 않으면 JSON을 처리하려고 할 때 에러가 납니다.
(2) JSON에서는 값이 문자열인 경우 큰따옴표(")를 사용해야 합니다.
const member = {
"name": 'Michael Kim',
"height": 180,
"weight": 70,
"hobbies": ['Basketball', 'Listening to music']
};
잠깐 member 객체를 다시 볼게요. 지금 name 프로퍼티의 값으로 'Michael Kim'이라는 문자열이 들어가 있죠? 자바스크립트에서는 문자열을 나타낼 때, 이렇게 작은따옴표(')를 써도 되고, 큰따옴표(")를 써서 "Michael Kim"이라고 써도 됩니다.
하지만 JSON에서는 문자열 값을
{
"name":"Michael Kim",
"height":180,
"weight":70,
"hobbies":["Basketball", "Listening to music"]
}
지금 보이는 "Michael Kim", "Basketball", "Listening to music"처럼 항상 큰따옴표로 감싸서 적어줘야만 합니다.
JSON에서는 표현할 수 없는 값들이 있습니다.
자바스크립트에서는 프로퍼티의 값으로 사용할 수 있는 undefined, NaN, Infinity 등을 JSON에서는 사용할 수 없습니다. 참고로, JSON은 비록 자바스크립트로부터 비롯된 데이터 포맷이지만, 그 탄생 목적은 언어나 환경에 종속되지 않고, 언제 어디서든 사용할 수 있는 데이터 포맷이 되는 것이었습니다. 따라서 자바스크립트의 문법에서만 유효한 개념을 JSON에서는 나타낼 수 없다는 것은 어찌 보면 당연한 결과입니다.
JSON에는 주석을 추가할 수 없습니다.
JSON은 코드가 아니라 데이터 포맷이기 때문에 그 안에 주석을 포함시킬 수 없습니다.
{ const users = JSON.parse(result) }
Request의 Head와 Body




POST request, PUT request
새 데이터를 추가하는 리퀘스트 - POST
기존 데이터를 수정하는 리퀘스트 - PUT
GET request, Delete request
기존 데이터를 조회하는 리퀘스트 - GET
기존 데이터를 삭제하는 리퀘스트 - DELETE
Web API, REST API
https://www.codeit.kr/topics/basics-of-js-web-dev/lessons/4353
https://www.codeit.kr/topics/basics-of-js-web-dev/lessons/4355
Status Code: response의 head 부분
각각의 상태 코드에는 대응되는 상태 메시지가 있고, 100번대부터 500번대까지 각 100 단위로 응답의 종류가 다름.
예: 200번은 OK, 404번은 Not Found
// status로 Status Code 출력 가능
fetch('https://www.google.com')
.then((response) => {
console.log(response.status);
});
const newMember = {
name: 'Jerry',
email: 'jerry@codeit.kr',
department: 'engineering',
};
fetch('https://learn.codeit.kr/api/members', {
method: 'POST',
headers: { // 추가된 부분
'Content-Type': 'application/json',
},
body: JSON.stringify(newMember),
})
.then((response) => response.text())
.then((result) => { console.log(result); });
https://www.codeit.kr/topics/basics-of-js-web-dev/lessons/4361
https://www.codeit.kr/topics/basics-of-js-web-dev/lessons/4362
.then들은 가장 마지막에 실행됨console.log('Start!');
fetch('https://www.google.com')
.then((response) => response.text()) // 콜백
.then((result) => { console.log(result); }); // 콜백
console.log('End');

console.log('a');
setTimeout(() => { console.log('b'); }, 2000);
console.log('c');
위의 코드에서, () ⇒ { console.log('b'); },를 2000밀리세컨드(=2초) 미룸
2. setInterval 함수: 특정 콜백을 일정한 시간 간격으로 실행하도록 등록하는 함수 (Interval는 '간격'이라는 뜻!)
console.log('a');
setInterval(() => { console.log('b'); }, 2000);
console.log('c');
// onclick
...
btn.onclick = function (e) { // 해당 이벤트 객체가 파라미터 e로 넘어옵니다.
console.log('Hello Codeit!');
};
// 또는 arrow function 형식으로 이렇게 나타낼 수도 있습니다.
btn.onclick = (e) => {
console.log('Hello Codeit!');
};
// addEventListener
...
btn.addEventListener('click', function (e) { // 해당 이벤트 객체가 파라미터 e로 넘어옵니다.
console.log('Hello Codeit!');
});
// 또는 arrow function 형식으로 이렇게 나타낼 수도 있습니다.
btn.addEventListener('click', (e) => {
console.log('Hello Codeit!');
});
setTimeout(콜백, 시간)
setInterval(콜백, 시간)
addEventListener(이벤트 이름, 콜백)
fetch('https://www.google.com')
.then((response) => response.text()) // fetch 함수가 리턴하는 객체의 then 메소드를 사용해서 콜백을 등록
// 작업 성공 결과가 response에 담김
.then((result) => { console.log(result); });
왜 fetch함수만 사용 형식이 다를까? Promise 객체를 리턴하기 때문!
Promise 객체: 작업에 관한 상태정보를 가지고 있는 객체
.then은 promise 객체가 pending에서 fulfilled 상태가 될 때 실행할 콜백을 등록하는 메소드, fetch 함수는 promise 객체를 리턴함
promise 객체의 3가지 상태


fulfilled 상태에서 promise 객체는 해당 작업의 성공 결과도 함께 가짐. fetch 함수의 경우에는 서버가 보내준 리스펀스가 작업 성공 결과에 해당함.
rejected 상태에서 promise 객체는 해당 작업 실패 이유에 관한 정보를 함께 가짐.
Promise Chaining: promise 객체에 then 메소드를 연속적으로 붙여서 연결해나가는 것
then 메소드는 새로운 promise 객체를 리턴하므로 가능함 (이 때 fulfilled, rejected는 첫 fetch함수와 일치함)
text, JSON 메소드도 Promise 객체를 리턴함
JSON.parse(result);처리해주기/*
기존 직원 정보에 신입 직원들의 정보를 추가한 다음, 모든 직원들의 명단을 출력할 것. 이 때,
두 번째 then 메소드에서 interviewee의 result가 pass인 직원 정보를 담은 newMembers를 return
세 번째 then 메소드에서 fetch 메소드의 body에 새로운 직원 정보를 직렬화하여 추가하는 리퀘스트를 보냈다.
네 번째 then 메소드에서 새로운 직원 정보의 추가가 잘 되었을 때 모든 직원 정보를 가져오는 리퀘스트를 보냈다.
총 직원 수와 모든 직원의 정보가 올바르게 출력된다.
*/
fetch('https://learn.codeit.kr/api/interviews/summer')
.then((response) => response.json())
.then((interviewResult) => {
const { interviewees } = interviewResult;
const newMembers = interviewees.filter((interviewee) => interviewee.result === 'pass');
return newMembers;
})
.then((newMembers) => fetch('https://learn.codeit.kr/api/members', {
method: 'POST',
body: JSON.stringify(newMembers),
}))
.then((response) => {
if (response.status === 200) {
return fetch('https://learn.codeit.kr/api/members');
} else {
throw new Error('New members not added');
}
})
.then((response) => response.json())
.then((members) => {
console.log(`총 직원 수: ${members.length}`);
console.log(members);
});
.then(fulfilled 상태에서 실행할 콜백, rejected 상태에서 실행할 콜백) → 각각 작업 실행 결과, 작업 실패 정보가 파라미터로 return됨const successCallback = function () { };
const errorCallback = function () { };fetch('https://jsonplaceholder.typicode.com/users') // Promise-A
.then(successCallback, errorCallback); // Promise-B
- fetch 함수의 작업이 성공해서 Promise-A 객체가 fulfilled 상태가 된 경우: then 메소드 안의 "첫 번째" 콜백인 successCallback이 실행되고 결과로 작업 성공 결과를 가짐
- fetch 함수의 작업이 실패해서 Promise-A 객체가 rejected 상태가 된 경우: then 메소드 안의 "두 번째" 콜백인 errorCallback이 실행되고 결과로 작업 실패 정보를 가짐
```js
/*
Case(1) : 콜백에서 Promise 객체를 리턴
Case(2) : 콜백에서 Promise 객체가 아닌 일반적인 값을 리턴
Case(3) : 콜백에서 아무것도 리턴하지 않음
Case(4) : 콜백 실행 중 에러 발생
Case(5) : 콜백이 실행되지 않음
*/
fetch('https://jsonplaceholder.typicode.com/users')
.then((response) => {
// return response.json(); // <- Case(1)
// return 10; // <- Case(2)
// // <- Case(3)
// throw new Error('failed'); // <- Case(4)
})
.then((result) => {
console.log(result);
});
// 존재하지 않는 URL
/* fetch('https://jsonplaceholder.typicode.commmmmm/users')
.then((response) => response.json()) // <- Case(5)
.then((result) => { }, (error) => { console.log(error) }); */
콜백에서 문자열 'Success' 리턴 ⇒ A는 fulfilled 상태가 되고, 문자열 'Success'를 작업 성공 결과로 갖는다.
콜백에서 pending 상태의 Promise 객체(B)를 리턴 ⇒ A는 B가 나중에 갖게되는 상태과 결과를 그대로 따라서 갖게 된다.
콜백에서 에러가 발생했을 때 ⇒ A는 rejected 상태가 되고, 해당 에러 객체를 작업 실패 정보로 갖게 된다.
아무런 콜백도 실행되지 않을 때 ⇒ A는, 호출된 then 메소드를 갖고 있는 이전 Promise 객체와 동일한 상태와 결과를 갖게 된다.
자바스크립트에서는 함수가 아무것도 리턴하지 않으면, undefined를 리턴한 것으로 봅니다. 따라서 콜백에서 아무것도 리턴하지 않아도 undefined를 리턴한 것으로 보아서, A는 fulfilled 상태가 되고, 작업 성공 결과로 undefined를 갖게 됩니다.
// Internet Disconnected
fetch('https://jsonplaceholder.typicode.com/users')
.then((response) => response.text())
.catch((error) => { console.log(error); })
.then((result) => { console.log(result); });
catch 메소드를 가장 마지막에 적어야 fetch 메소드의 작업이 실패해서 발생하는 오류와 인위적으로 발생시키는 오류(인터넷이슈, URL 부정확)들에 모두 대응할 수 있음
.catch(callback) == .then(undefined, callback)
finally 메소드: 만약 어떤 작업의 성공과 실패여부에 무관하게, 즉, promise 객체가 fulfilled 상태이건 rejected 상태이건 상관없이 실행하고자 하는 콜백을 등록하는 메소드로, 파라미터가 필요하지 않음
Promise 객체의 등장 이유
setTimeout(callback, milliseconds);
addEventListener(eventname, callback);
fetch('https://first.com', callback)
직접 만든 promise 객체로 대체가 가능한 함수: 기존의 비동기 실행 함수들 중에서도 그 콜백을 한번만 실행하는 것들(setTimeout, readFile 등)만 Promisify해서 사용해도 괜찮음
직접 만든 promise 객체로 대체가 불가능한 함수:콜백을 여러 번 실행하는 함수들(setInterval, addEventListener 등) - 이유: Promise 객체는 한번 pending 상태에서 fulfilled 또는 rejected 상태가 되고나면 그 뒤로는 그 상태와 결과가 바뀌지 않기 때문
// new로 객체를 만듦
const p = new Promise((resolve, reject) => {
// executor 함수
// resolve: 생성될 promise 객체를 fulfilled 상태로 만들 수 있는 함수가 연결됨
// reject: 생성될 promise 객체를 rejected 상태로 만들 수 있는 함수가 연결됨
});
// fulfilled 상태의 Promise 객체 만들기
const p = Promise.resolve('success');
// rejected 상태의 Promise 객체 만들기
const p = Promise.reject(new Error('fail'));
// 1번 직원 정보
const p1 = fetch('https://learn.codeit.kr/api/members/1').then((res) => res.json());
// 2번 직원 정보
const p2 = fetch('https://learn.codeit.kr/api/members/2').then((res) => res.json());
// 3번 직원 정보
const p3 = fetch('https://learn.codeit.kr/api/members/3').then((res) => res.json());
Promise
.all([p1, p2, p3])
.then((results) => {
console.log(results); // Array : [1번 직원 정보, 2번 직원 정보, 3번 직원 정보]
});
race 메소드는 all 메소드와 마찬가지로 여러 Promise 객체들이 있는 배열을 아규먼트로 받고 all 메소드처럼 Promise 객체를 리턴하지만 그 적용 원리가 다름
race 메소드가 리턴한 Promise 객체는 아규먼트로 들어온 배열의 여러 Promise 객체들 중에서
가장 먼저 fulfilled 상태 또는 rejected 상태가 된 Promise 객체와 동일한 상태와 결과를 갖게 됨
allSettled 메소드 : 배열 내의 모든 Promise 객체가 fulfilled 또는 rejected 상태가 되기까지 기다리고, pending 상태의 Promise 객체가 하나도 없게 되면, 리턴한 Promise 객체의 상태값은 fulfilled 상태가 되고 그 작업 성공 결과로, 하나의 배열을 갖게 됨
any 메소드 : 여러 Promise 객체들 중에서 가장 먼저 fulfilled 상태가 된 Promise 객체의 상태와 결과가 리턴한 Promise 객체에도 똑같이 반영됩니다. 만약 모든 Promise 객체가 rejected 상태가 되어버리면 AggregateError라고 하는 에러를 작업 실패 정보로 갖고 rejected 상태가 됩니다. any라는 단어의 뜻처럼 배열 속의 Promise 객체 중 단 하나라도 fulfilled 상태가 되면 되는 겁니다.
// axios 패키지에서 제공하는 axios 객체를 사용해서 GET 리퀘스트를 보내고 그 리스폰스를 받는 코드
axios
.get('https://jsonplaceholder.typicode.com/users')
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error);
}); // fetch 함수처럼 promise 객체를 리턴
async/await 구문
async는 함수 안에 비동기적으로 실행할 부분이 있다는 뜻으로, 이 부분을 지칭하는 것이 await임
await는 뒤에 있는 코드를 실행하고 그것이 리턴하는 promise 객체가 fulfilled 상태가 될 때까지 기다린 후 작업 성공 결과를 추출해서 리턴하기.
await 키워드는 async 함수 안에서만 사용이 가능함
동기코드처럼 생긴 비동기 실행코드 ,,,,
(1) 개발자가 더 편하게 작성할 수 있도록 하고
(2) 코드의 가독성을 높이기 위해서
/* fetch('https://www.google.com')
.then((response) => response.text())
.then((result) => { console.log(result); }); */
async function fetchAndPrint() {
console.log(2);
const response = await fetch('https://jsonplaceholder.typicode.com/users');
console.log(7);
const result = await response.text();
console.log(result);
}
console.log(1);
fetchAndPrint();
console.log(3);
console.log(4);
console.log(5);
console.log(6);
// promising Chaining
async function getTheLastPostOfTheLastUser() {
const usersJSON = await fetch("https://jsonplaceholder.typicode.com/users");
const users = await usersJSON.json();
const lastUser = users[users.length - 1];
const { id } = lastUser;
const postsJSON = await fetch(`https://jsonplaceholder.typicode.com/posts?userId=${id}`);
const posts = await postsJSON.json();
const lastPost = posts[posts.length - 1];
return lastPost;
}
getTheLastPostOfTheLastUser().then((lastPost) => {
console.log(lastPost);
});
// async/await
fetch("https://jsonplaceholder.typicode.com/users")
.then((response) => response.json())
.then((users) => {
const lastUser = users[users.length - 1];
return lastUser.id;
})
.then((id) => fetch(`https://jsonplaceholder.typicode.com/posts?userId=${id}`))
.then((response) => response.json())
.then((posts) => {
const lastPost = posts[posts.length - 1];
console.log(lastPost);
});
async function getTheLastPostOfTheLastUser() {
const usersJSON = await fetch("https://jsonplaceholder.typicode.com/users");
const users = await usersJSON.json();
const lastUser = users[users.length - 1];
const { id } = lastUser;
const postsJSON = await fetch(`https://jsonplaceholder.typicode.com/posts?userId=${id}`);
const posts = await postsJSON.json();
const lastPost = posts[posts.length - 1];
return lastPost;
}
getTheLastPostOfTheLastUser().then((lastPost) => {
console.log(lastPost);
});
const p1 = fetch('https://jsonplaceholder.typicode.com/users?id=1')
.then((response) => response.text());
const p2 = new Promise((resolve, reject) => {
setTimeout(() => { resolve('hello'); }, 2000);
});
const p3 = Promise.resolve('Success');
// const p4 = Promise.reject(new Error('Fail'));
async function test() {
console.log(await p1);
console.log(await p2);
console.log(await p3);
// console.log(await p4);
}
console.log('----Start----');
test();
console.log('-----End----');
// 출력: Start, End, response 내용
async function fetchAndPrint() {
const response = await fetch('https://www.google.com');
const result = await response.text();
console.log(result);
}
console.log('Start');
fetchAndPrint();
console.log('End');
// 출력: JavaScript - Programming - success - fail - last
async function test1() {
const result = await Promise.resolve('success');
console.log(result);
}
async function test2() {
try {
const p = new Promise((resolve, reject) => {
setTimeout(() => { resolve('last'); }, 3000);
});
const result = await p;
console.log(result);
} catch (e) {
console.log(e);
}
}
async function test3() {
try {
const result = await Promise.reject('fail');
console.log(result);
} catch (e) {
console.log(e);
}
}
test1();
console.log('JavaScript');
test2();
console.log('Programming');
test3();
async function fetchAndPrint()
{
try {
const response = await fetch('https://google.com');
const result = await response.text();
console.log(result);
} catch (error) {
console.log(error);
}
}
async function fetchAndPrint() {
return new Promise((resolve, reject)=> {
setTimeout(() => { resolve('abc'); }, 4000);
});
}
fetchAndPrint();
(2) Promise 객체 이외의 값을 리턴하는 경우: async 함수 내부에서 Promise 객체 이외에 숫자나 문자열, 일반 객체 등을 리턴하는 경우에는fulfilled 상태이면서 리턴된 값을 작업 성공 결과로 가진 Promise 객체를 리턴
async function fetchAndPrint() {
return 3;
}
fetchAndPrint();
async function fetchAndPrint() {
console.log('Hello Programming!');
}
fetchAndPrint();
async function fetchAndPrint() {
throw new Error('Fail');
}
fetchAndPrint();
// 1) Function Declaration
async function example1(a, b) {
return a + b;
}
// 2-1) Function Expression(Named)
const example2_1= async function add(a, b) {
return a + b;
};
// 2-2) Function Expression(Anonymous)
const example2_2 = async function(a, b) {
return a + b;
};
// 3-1) Arrow Function
const example3_1 = async (a, b) => {
return a + b;
};
// 3-2) Arrow Function(shortened)
const example3_2 = async (a, b) => a + b;
(async function print(sentence) {
console.log(sentence);
return sentence;
}('I love JavaScript! well...'));
(async function (a, b) {
return a + b;
}(1, 2));
(async (a, b) => {
return a + b;
})(1, 2);
(async (a, b) => a + b)(1, 2);
https://www.codeit.kr/topics/basics-of-js-web-dev/lessons/4114
https://www.codeit.kr/topics/basics-of-js-web-dev/lessons/4399