
📅 2025-09-19
➡️ JavaScript fetch와 localStorage에 대해 새롭게 알게 된 것 또는 헷갈리는 부분 정리 + 🤔❓
JSON이란?
형태
")로 묶어야 함{ "title": "책 제목", "price": 12000 }
JSON.stringify() 사용주로 서버 전송이나 브라우저 저장소(localStorage)에 데이터를 넣을 때 필요
const user = { name: "홍길동", age: 25 };
const jsonStr = JSON.stringify(user);
console.log(jsonStr);
// 출력: {"name":"홍길동","age":25}
JSON.parse() 사용서버 응답이나 파일에서 읽어온 JSON 문자열을 실제로 다룰 수 있게 객체로 바꿈
const jsonStr = '{"name":"홍길동","age":25}';
const user = JSON.parse(jsonStr);
console.log(user.name); // "홍길동"
console.log(user.age); // 25
Promise 객체로 돌려줌 
.then()이나 async/await을 사용해서 응답을 처리할 수 있도록 도와주는 비동기 통신 도구fetch(주소).then((파라미터이름) => {
return 파라미터이름.json();
}).then((필요한데이터) => { // 데이터 사용
console.log(필요한데이터)})
fetch의 인자로 주소 작성.then(함수) 작성return 파라미터 .json() 작성then을 한 번 더 작성 및 파라미터 사용Promise 객체는 바로 값이 나오지 않으니, 결과를 활용하려면 .then()을 써야 함.then() 안의 콜백 함수 파라미터로 실제 결과를 받을 수 있음fetch("https://jsonplaceholder.typicode.com/todos/1")
.then((response) => {
console.log(response); // Response 객체
});

fetch("https://jsonplaceholder.typicode.com/todos/1")
.then((response) => {
return response.json() // Promise
})
.then((data) => {
console.log(data);
})
.catch((err) => console.error(err));
//fetch(주소).then((파라미터이름) => {return 파라미터이름.json();})
fetch("https://jsonplaceholder.typicode.com/todos/1")
.then((response) => {
return response.json(); // JSON 변환도 Promise
})
.then((data) => {
console.log(data);
});
.json()으로 호출하면 body을 JSON을 반환할 수 있음. 다만 이 메서드도 Promise를 반환하니 .then() 을 이어 붙여야 해요왜 이렇게 동작할까?
fetch는 외부에서 데이터를 가져오는 시간이 오래 걸리는 작업임- 오래 걸릴 수 있는 코드는 비동기로 실행하여 다음 코드가 계속 진행하도록 만든 것이 더 좋음
- 대신 오래 걸리는 작업이 끝나면
.then()함수로 결과가 전달하는 방식으로 작동
🔗 https://jsonplaceholder.typicode.com/
<script>
fetch("https://jsonplaceholder.typicode.com/users")
.then((response) => {
console.log(response); // Response 객체
return response.json();
}).then((data) => {
console.log(data);
});
</script>
// fetch(주소, 설정값)
fetch(url, options)options는 객체(Object) 형태로 작성여기에 요청 방식, 인증 정보, 요청 헤더 등을 담음
const options = {
method: "GET", // 어떤 방식으로 요청할지
headers: { // 요청 헤더(추가 정보)
accept: "application/json", // 응답을 JSON으로 받고 싶다
Authorization: "Bearer 토큰값", // 인증이 필요한 경우
},
};
왜 필요한가?
- 서버에서(백앤드 개발자) 추가적인 정보를 요청한 경우
- method
GET,POST,PUT,PATCH,DELETE- headers
-accept: "application/json": 응답을 JSON으로 받고 싶다
-Authorization: 인증이 필요한 경우
GET /posts/1 HTTP/1.1
Host: jsonplaceholder.typicode.com
Accept: application/json

GET (조회)fetch("https://jsonplaceholder.typicode.com/users", { method: "GET" })
// method 생략 가능
fetch("https://jsonplaceholder.typicode.com/users")
// 의미: 유저 데이터 여러개를 조회(GET)한다
// GET 메소드는 생략 가능 기본 default값POST (생성)fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
body: JSON.stringify({
title: '자바스크립트',
category: 'front',
userId: 1,
}),
headers: {
'Content-type': 'application/json; charset=UTF-8',
},
})
.then((response) => response.json())
.then((json) => console.log(json));PUT (전체 수정)fetch('https://jsonplaceholder.typicode.com/posts/1', {
method: 'PUT',
body: JSON.stringify({
id: 1,
title: 'HTML ',
body: 'front 기초',
userId: 1,
}),
headers: {
'Content-type': 'application/json; charset=UTF-8',
},
})
.then((response) => response.json())
.then((json) => console.log(json));PATCH (부분 수정)fetch('https://jsonplaceholder.typicode.com/posts/1', {
method: 'PATCH',
body: JSON.stringify({
title: 'React JS',
}),
headers: {
'Content-type': 'application/json; charset=UTF-8',
},
})
.then((response) => response.json())
.then((json) => console.log(json));DELETE (삭제)fetch('https://jsonplaceholder.typicode.com/posts/1', {
method: 'DELETE',
});200 OK (성공)201 Created (POST 성공)===============================
400 Bad Request (내가 이상하게 보냄)401/403 인증/권한 문제404 Not Found (주소/리소스 없음)500 Server Error (서버 쪽 문제)왜 메서드가 중요한가?
HTTP 프로토콜에서는 같은 URL을 사용해도, 메서드에 따라 전혀 다른 요청이 됨
GET /users/1 → 1번 유저 조회 DELETE /users/1 → 1번 유저 삭제메서드 + URL 조합이 요청의 의미를 정의하는 규칙
이를 RESTful API 디자인이라고 함
Promise를 .then() 체인으로 쓰면 결과 값을 오직 .then() 내부에서만 다룰 수 있어 불편하고, 가독성이 떨어짐await/async 문법을 사용// 1. .then을 제거 await를 앞에 붙입니다.
await fetch("https://jsonplaceholder.typicode.com/posts");
// 2. .then의 콜백함수 파라미터에 들어가는 데이터를 변수로 받습니다.
const response = await fetch("https://jsonplaceholder.typicode.com/posts");
// 3. .then을 날리고 이전의 return 에 있는 코드 앞에 await를 붙입니다.
await response.json();
// 4. 다음 .then의 콜백함수 파라미터에 들어가는 데이터를 변수로 받습니다.
const data = await response.json();
// 결과
const response = await fetch("https://jsonplaceholder.typicode.com/posts");
const data = await response.json();
// await/async 일반적으로 함수 안에서만 사용함
async function getPosts() {
const response = await fetch("https://jsonplaceholder.typicode.com/posts");
const data = await response.json();
console.log(data)
}
getPosts();try {
const response = await fetch("https://jsonplaceholder.typicode.com/comments");
const data = await response.json();
} catch(error) {
console.log(error);
}
response의 객체를 먼저 확인
200번대) 이어도 서버 응답 자체가 실패 상태일 수 있음async function safeFetch(url, options) {
const res = await fetch(url, options);
if (!res.ok) {
// 상태코드 포함한 에러로 던지기
throw new Error(`HTTP ${res.status}: ${res.statusText}`);
}
return res.json();
}
에러는 throw, UI는 바깥에서 처리
async function load() {
try {
const data = await safeFetch("/api/posts");
// UI 업데이트
renderPosts(data); // renderPosts 함수로 화면 업데이트
} catch (e) {
// 여기서 사용자에게 안내
}
문자열(String)로만 저장 가능
JSON.stringify() 해서 저장JSON.parse()로 다시 객체화영구적 저장
브라우저 전용 저장소
localStorage.setItem(key, value) → 저장
// 상품 리스트 저장
const products = [
{ id: 1, brand: "아디다스", name: "멋진 아디다스 반팔티", price: 32000 },
{ id: 2, brand: "나이키", name: "멋진 나이키 바지", price: 30000 },
];
localStorage.setItem("products", JSON.stringify(products));
localStorage.getItem(key) → 불러오기
const newProduct = { id: 3, brand: "뉴발", name: "멋진 뉴발 신발", price: 78000 };
const products = JSON.parse(localStorage.getItem("products"));
localStorage.setItem("products", JSON.stringify([...products, newProduct]));
localStorage.removeItem(key) → 특정 데이터 삭제
const products = JSON.parse(localStorage.getItem("products"));
const filtered = products.filter((p) => p.id !== 1);
localStorage.setItem("products", JSON.stringify(filtered));
localStorage.clear() → 전체 삭제
localStorage.clear();
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<title>localStorage 실습</title>
</head>
<body>
<h2>📦 localStorage 기본 예제</h2>
<button id="btnSave">1. 상품 저장 (setItem)</button>
<button id="btnAdd">2. 상품 추가 (getItem + setItem)</button>
<button id="btnDeleteOne">3. 상품 삭제 (removeItem / filter)</button>
<button id="btnClear">4. 전체 삭제 (clear)</button>
<button id="btnShow">현재 상태 확인</button>
<pre id="output">결과가 여기에 표시됩니다.</pre>
<script>
const output = document.getElementById('output');
// 1. 상품 저장
document.querySelector('#btnSave').addEventListener('click', () => {
const products = [
{
id: 1,
brand: '아디다스',
name: '멋진 아디다스 반팔티',
price: 32000,
},
{
id: 2,
brand: '나이키',
name: '멋진 나이키 반팔티',
price: 30000,
},
];
localStorage.setItem('products', JSON.stringify(products));
output.innerHTML = '상품 저장 완료';
});
// 2. 상품 추가
document.querySelector('#btnAdd').addEventListener('click', () => {
console.log('add Btn');
const newProduct = {
id: 3,
brand: '뉴발',
name: '멋진 뉴발 신발',
price: 70000,
};
const products = JSON.parse(localStorage.getItem('products'));
localStorage.setItem('products', JSON.stringify([...products, newProduct]));
output.innerHTML = '상품 추가 완료';
});
// 3. 상품 삭제 (특정 상품)
document.querySelector('#btnDeleteOne').addEventListener('click', () => {
const products = JSON.parse(localStorage.getItem('products'));
const filteredList = products.filter((product) => product.id !== 1);
console.log(filteredList);
localStorage.setItem('products', JSON.stringify(filteredList));
output.innerHTML = '상품 삭제 완료 id = 1';
});
// 4. 상품 삭제
document.querySelector('#btnClear').addEventListener('click', () => {
localStorage.clear();
output.innerHTML = '상품 전체 삭제';
});
// 5. 현재 상태 확인
document.querySelector('#btnShow').addEventListener('click', () => {
const product = localStorage.getItem('products');
output.innerHTML = product;
});
</script>
</body>
</html>
➡️ EXP 미션 중 궁금해진 내용 정리
innerHTML은 DOM을 직접적으로 수정하기 때문에, innerHTML은 실행될 때마다 기존 DOM을 모두 다시 파싱 및 렌더링하므로, 반복 사용 시 성능 저하 발생createElement()처럼 요소를 새롭게 생성하고 DOM 트리에 추가하는 방식이 더 효율적임❗ 사용자로부터 입력 받은 데이터를 그대로 innerHTML 프로퍼티에 할당하는 것은 크로스 사이트 스크립팅 공격(XSS)에 취약하므로 위험
let element = document.createElement(tagName[, options]);
tagName의 HTML 요소를 만들어 반환❗ 요소 노드를 생성할 뿐 DOM에 추가하지는 않음 → 별도 처리 필요
→append()/appendChild()
🔗 https://developer.mozilla.org/ko/docs/Web/API/Document/createElement
🔗 https://www.javascripttutorial.net/javascript-dom/javascript-innerhtml-vs-createelement/
Node 객체와 문자열 모두 인수로 받을 수 있음undefined)Node 객체만을 인수로 받을 수 있음Node 객체 반환const parent = document.getElementById('posts');
const div1 = document.createElement('div');
const div2 = document.createElement('div');
parent.append(div1, div2, '텍스트도 가능'); // append
parent.appendChild(div1); // appendChild
📎 https://developer.mozilla.org/ko/docs/Web/API/Document/append
📎 https://developer.mozilla.org/ko/docs/Web/API/Node/appendChild