본문 바로가기
IT 인터넷

JSON은 형식일뿐? JSON 문자열 vs JS 객체 / res.json() = JSON.parse()

by 로맨틱스터디 2025. 11. 17.
728x90
반응형

좋아, 이 질문은 많은 개발자가 헷갈리는 핵심 포인트이므로
완전히 깔끔하게 정리해줄게.
결론부터 말하면: JSON은 “데이터를 표현하는 텍스트 형식”일 뿐 객체가 아니다.


🎯 핵심 결론 4줄 요약

  1. JSON은 오직 “문자열 형식(text format)”이다.
    즉, 파일·응답·문자열일 뿐 객체가 아니다.
  2. “JSON 객체”라는 표현은 사실 틀린 말이다.
    정확한 말은 JSON 구조를 담고 있는 문자열(JSON text)”.
  3. JavaScript 객체는 실제 메모리에 존재하는 js 엔진의 데이터 구조다.
  4. JSON 문자열을 파싱(분석)하면 -> JavaScript 객체가 만들어지는 것.
    둘은 완전히 다른 것!

1️⃣ JSON이란 무엇인가?

JSON의 정의:

JavaScript Object Notation (자바스크립트 객체 표기법)
데이터를 표현하기 위한 문자열 기반의 표준 포맷(format)

 

즉 JSON은 문자열 규칙의 집합이다.

 

JSON은 이런 규칙을 가진 텍스트:

{
  "name": "Hong",
  "age": 20
}

 

이것은 사람이 보면 객체처럼 생겼지만(JS 객체 표기법),
브라우저·서버가 받는 건 100% 문자열이다.

 

예)

"{\"name\":\"Hong\",\"age\":20}"

2️⃣ “JSON 문자열” vs “JavaScript 객체”

✔ JSON 문자열 (text)

"{\"x\":1}"
  • 단순한 텍스트 문자열
  • 네트워크로 주고받는 데이터
  • 저장되는 값
  • JS 엔진은 이걸 객체로 인식하지 않음

✔ JavaScript 객체 (in-memory object)

{ x: 1 }
  • 메모리에 실제로 존재하는 구조체
  • 속성 접근 가능(x.y)
  • 프로토타입 체인을 가짐
  • 메서드를 가짐 (toString 등)

3️⃣ JSON 문자열을 파싱 → JavaScript 객체 생성

예:

JSON.parse('{"x":1}')
{ x: 1 }.  // JS 객체

 

반대로:

JSON.stringify({ x: 1 })
→ '{"x":1}'  // JSON 문자열

 

즉:

JSON(string) JS Object
저장용 실행/조작
텍스트 메모리 구조
네트워크용 프로그램 내부
따옴표 규칙 강제 규칙 자유로움

4️⃣ “JSON 객체”라는 말은 틀린 표현이다

많은 사람들이 이렇게 말함:

  • “JSON 객체”
  • JSON 형태의 객체”

하지만 기술적으로 정확한 표현은:

  • JSON 문자열(JSON text)
  • JSON 데이터(JSON formatted string)

왜냐하면 JSON은 실제로는 객체가 아니기 때문.

기술적으로 ECMAScript 명세에서는 이렇게 정의함:

JSON is a string representation of structured data.


5️⃣ JSON과 JavaScript 객체가 생긴 것이 비슷한 이유

JSON의 문법이 JS 객체 리터럴(Object literal) 문법을 기반으로 만들어졌기 때문.

그래서 생긴 게 비슷함:

 

JS 객체:

{ x: 1 }

 

JSON:

{ "x": 1 }

 

하지만 규칙이 다름:

규칙 JS 객체 JSON
속성 이름 따옴표 없어도 됨 반드시 쌍따옴표
함수 가능 함수 ❌
undefined 있음
Infinity, NaN 있음
주석 가능

즉, JSON은 더 엄격한 텍스트 규칙이다.


6️⃣ 최종적으로 정리하면

✔ JSON은 “문자열”이다

파일, 네트워크 응답, 텍스트로 존재한다.

✔ JavaScript 객체는 “메모리의 실제 객체”이다

프로토타입·메서드·참조 등이 존재.

✔ JSON 문자열을 → 파싱하면 → JS 객체가 됨

그래서 둘이 “생긴 건 비슷하지만 완전히 다른 존재”.


📌 아주 짧게 요약

"JSON은 객체처럼 생긴 문자열일 뿐이다."

"JS 객체는 진짜 객체다."

"res.json()은 JSON 문자열을 JS 객체로 바꾼다."


원하면:

  • JSON의 전체 문법 규칙
  • 왜 JSON은 프로토타입이 없는가
  • JSON.stringify 커스텀 replacer
  • JSON.parse reviver 함수

이런 것들도 자세히 설명해줄게!

 

Q. 파싱

더보기

좋아, "파싱(parsing)"이란 무엇인가를 가장 직관적으로, 어려운 말 절대 없이 설명해줄게.


🎯 아주 간단한 정의

파싱 =

어떤 형식의 “문자열”을 → 의미 있는 구조(데이터)로 분석/변환하는 과정.

 

즉 문자열을 해석해서 구조화하는 것.


🧠 한 줄로 요약하면

문자열을 읽어서컴퓨터가 이해할 수 있는 데이터 구조로 바꾸는 것”

이게 파싱이다.


📌 예시 1: JSON 파싱

JSON 문자열:

"{\"name\": \"Tom\", \"age\": 20}"

이건 그냥 문자의 나열이다.

 

이걸 JS 객체로 변환하는 게 파싱:

JSON.parse("{\"name\": \"Tom\", \"age\": 20}")
→ { name: "Tom", age: 20 }

즉 문자열을 → 객체로 변환한 것.


📌 예시 2: URL 파싱

문자열 URL:

https://example.com:3000/path?q=10

 

이걸 브라우저는 이렇게 구분한다:

  • scheme: https
  • host: example.com
  • port: 3000
  • path: /path
  • query: q=10

브라우저가 이 문자열을 해석해서 쪼개는 것 = URL parsing


📌 예시 3: HTML 파싱

HTML 문자열:

<div>Hello</div>

브라우저는 이걸 읽어 div DOM 요소를 만든다.

이 과정 = HTML 파싱


📌 예시 4: 숫자 파싱

문자열 "123" 을 숫자 123 으로 바꾸는 것:

parseInt("123") → 123

이것도 파싱이다.


📌 파싱이란 결국…

문자열단순 문자 덩어리로 읽는 게 아니라
의미 있는 “구조”로 변환하는 것.

 

그래서 파서는 다음을 해야 한다:

  • 문자 하나하나 읽기
  • 문법에 맞는지 검사하기
  • 구조 분석하기(트리 만들기 등)
  • 최종적으로 데이터 구조 / 객체 변환

📌 왜 JSON을 파싱해야 할까?

서버는 항상 JSON을 문자열로 보낸다:

{"x":1}

이건 사람이 보면 객체처럼 보이지만,
컴퓨터 입장에서는 그냥 텍스트일 뿐.

그래서 이걸 JS 객체로 만들려면 파싱이 필요:

 
res.json() → 내부적으로 JSON.parseJS 객체 생성

📌 비유로 설명하면

문자열은 레시피 책이고
파싱은 레시피를 읽어서 -> 실제 음식 재료/구조를 만드는 과정이다.


🔥 진짜로 완전 짧게 정리하면

파싱 = 텍스트를 의미 있는 데이터로 바꾸는 것.


원하면:

  • 파싱 알고리즘(토큰화, AST 생성 과정)
  • 파싱 오류가 왜 발생하는지
  • 브라우저의 HTML 파서 동작 과정

이런 것도 더 깊게 알려줄게!


 

res.json() 은 **fetch()의 응답(Response 객체)**에 있는 메서드로,
서버에서 받은 응답 바디(body)를 -> JSON으로 파싱해서 -> JavaScript 객체로 변환해주는 함수야.

 

이게 어떤 식으로 동작하는지 정확히 설명해줄게.


✅ 1. res.json() 의 정확한 의미

fetch 후 서버 응답 객체 Response 타입이야:

fetch("/api/user")
  .then(res => res.json()) // ← 이게 JSON 파싱
  .then(data => console.log(data));
fetch("/api/user")
   .then(res => res.json())                   // ← 이게 JSON 파싱
   .then(data => console.log(data));

 

res.json() 은 다음 두 일을 함:

✔ 1) 응답 body 스트림을 모두 읽는다

(응답이 조각(chunk)으로 오면 모두 합침)

✔ 2) 그 문자열을 JSON.parse() 로 파싱한다

즉:

JSON.parse(responseText)

과 동일한 작업을 한다.


🧠 중요한 포인트: res.json()은 Promise를 반환한다

즉, res.json()은 즉시 결과 객체가 아니라 **비동기(Promise)**야.

const data = res.json(); // ❌ data는 아직 데이터가 아니라 Promise

 

맞는 코드는:

res.json()
  .then(data => { console.log(data); });

 

또는 async/await:

const res = await fetch("/api/user");
const data = await res.json();
console.log(data);

⚠ res.json()은 응답 body가 JSON이 아닐 때 에러

서버가 다음 같은 내용을 보냈는데:

Hello World

 

이걸 .json()으로 읽으면 오류:

Unexpected token H in JSON at position 0

 

그래서 종종 응답 타입 체크 후 json() 호출하기도 함:

if (res.headers.get("content-type")?.includes("application/json")) {
  const data = await res.json();
}

🎯 res.json() >= JSON.parse()보다 안전하고 편한 이유

✔ fetch는 응답 body가 “스트림”이라 json()이 필요함

단순히 문자열이 아님 → 네트워크로 들어오는 스트림.

✔ JSON을 문자열로 먼저 받지 않아도 됨

XHR에서는:

JSON.parse(xhr.responseText)

 

fetch는:

await res.json();

 

이 자체로 스트림문자열객체 변환이 이루어짐.


🔍 Response 객체에는 json() 말고도 다른 파서들도 있어

메서드 설명
res.json() JSONJS 객체
res.text() 문자열 그대로 반환
res.blob() 이미지/파일 blob
res.arrayBuffer() 바이너리 raw 데이터
res.formData() multipart/form-data 응답 처리

즉, 서버가 보내는 데이터 타입에 따라 골라쓰는 것.

 

예)
이미지라면:

const imgBlob = await res.blob();

 

텍스트라면:

const text = await res.text();

⭐ 정리

res.json()은:

  • fetch Response메서드
  • 응답 body 스트림을 완전히 읽고
  • JSON.parse()를 적용하며
  • Promise로 결과 객체를 반환하는 함수

한 줄로 적으면:

Response body → 스트림을 읽음 → 문자열로 합침 → JSON.parse() → JS 객체 반환


원하면:

  • fetch의 body 스트림 구조
  • 왜 json()만 먼저 한 번만 호출할 수 있는지
  • fetch와 XHR의 응답 파싱 차이
    도 설명해줄게!
728x90

 

Q. JSON 문자열 vs JS 객체

더보기

좋아, 이 부분은 “JSON 문자열” 과 “JavaScript 객체(진짜 객체)” 를 구분하면 바로 이해된다.
지금 헷갈린 지점은 JSON ≠ JavaScript 객체 라는 사실 때문이야.


🎯 핵심 결론

서버에서 보내는 JSON은 “문자열”이다.
res.json() 은 이 문자열을 -> 자바스크립트 객체변환(parse) 하는 함수다.

 

즉:

  • 서버 → JSON 문자열
  • 브라우저(fetch) → JSON 문자열을 객체로 파싱

이 과정이 res.json() 이 하는 일.


1️⃣ 서버에서 보내는 건 “JSON 객체”가 아니라 “JSON 문자열

서버는 실제로 이렇게 보냄:

{ "name": "홍길동", "age": 20 }

 

이것은 그냥 텍스트 문자열임

 

예를 들면:

"{\"name\":\"홍길동\",\"age\":20}"

 

HTTP 응답 바디는 기본적으로 문자열 데이터이다.
(바이너리, 스트림일 수도 있지만 기본은 문자열)

 

JSON 형식일 뿐이지 자바스크립트 객체는 절대 아니다.


2️⃣ “JSON으로 파싱한다”는 말의 진짜 의미

✔ 문자열(JSON text)을

✔ JavaScript 객체로 바꾸는 것

 

즉:

"{\"name\": \"홍길동\"}"   ← JSON 문자열
→ JSON.parse()
→ { name: "홍길동" }      ← JavaScript 객체

그 변환을 fetch의 res.json()이 해준다.


3️⃣ res.json() 의 내부는 결국 JSON.parse

직접 보면 느낌이 잡혀.

 
const response = await fetch("/api");
const obj = await response.json();

 

이때 response.json() 은

  1. 응답 바디를 읽는다 → 문자열
  2. JSON.parse(문자열)를 호출한다 → JS 객체 반환

즉:

response.json() ≈ JSON.parse(responseBody)

4️⃣ 그래서 응답 바디가 JSON 형식이 아니면 오류

예:

응답 바디가:

Hello World

이런 텍스트라면 JSON.parse 가 실패함.

→ res.json() 도 똑같이 에러 발생.

 

즉 "JSON 아닌걸 JSON으로 파싱"하려 했으니까 당연한 에러.


5️⃣ 왜 이렇게 설계했을까?

HTTP 응답은 기본적으로 "문자열"이기 때문.

브라우저는 다음을 구분하지 못함:

  • 이것이 JSON 객체인지
  • 단순 텍스트인지

오직 “문자열 + Content-Type 헤더”만 보고 결정 가능.

 

서버가 응답 헤더에 이렇게 보내면:

Content-Type: application/json

브라우저는 "아 이것 JSON이겠구나" 정도로 추측할 뿐…

그래서 실제 파싱은 개발자가 res.json()으로 직접 해야 한다.


6️⃣ 진짜 예시로 더 확실하게

서버 응답:

{"x":1,"y":2}

 

브라우저가 실제로 받은 것은:

 
"{"x":1,"y":2}"
   ↑
문자열

 

res.json() 실행 후:

{ x: 1, y: 2 }
   ↑
객체

문자열 → 객체 변환이 발생했지?

그래서 "JSON을 JSON으로 파싱한다"가 아니라
JSON 문자열 → JavaScript 객체로 파싱한다가 정확한 표현이야.


📌 마지막 정리

서버:

  • JSON항상 “문자열(text)”이다.

브라우저(fetch):

  • 응답문자열로 받아진다.
  • res.json() = JSON 문자열 → JS 객체로 변환
  • 응답이 JSON 형식이 아니면 에러.

원하면:

  • res.text(), res.blob(), res.arrayBuffer() 차이
  • Content-Type 헤더와 파싱 관계
  • JSON과 JavaScript 객체의 차이(규칙 vs 실제 객체)

이런 것도 더 설명해줄게!

Q. parseInt()

더보기

parseInt() 는 문자열(string)을 -> 정수(integer) 숫자 바꿔주는 JavaScript 내장 함수야.


📌 1. 기본 개념

parseInt("123") // → 123 (숫자)

문자열을 읽어서 앞에서부터 숫자라고 해석할 수 있는 부분만 정수로 변환한다.


📌 2. 중요한 특징

✔ 앞에서부터 숫자로 읽을 수 있는 부분까지만 변환

parseInt("123abc") // → 123
parseInt("10px") // → 10
parseInt("3.14") // → 3 (정수만!)

숫자로 못 읽는 지점에서 멈춘다.


첫 글자가 숫자가 아니면 NaN

parseInt("abc123") // → NaN

공백은 무시하고 시작

parseInt(" 42") // → 42

정수만 변환한다

소수점은 정수 부분만 빼고 버림.

parseInt("5.99") // → 5

소수점을 제대로 처리하려면 parseFloat() 사용.


📌 3. 진수(radix) 지정 가능

두 번째 인자를 주면 문자열을 몇 진수로 해석할지 정할 수 있다.

parseInt("FF", 16) // → 255 (16진수)
parseInt("1010", 2) // → 10 (2진수)
parseInt("20", 8) // → 16 (8진수)
 

📌 4. 숫자로만 이루어진 문자열일 때는 Number() 로도 가능

Number("123") // → 123

 

하지만 Number() 는 문자열 전체가 완벽한 숫자여야 한다.

Number("10px") // → NaN
parseInt("10px") // → 10 ← 더 관대함

📌 5. parseInt() 언제 쓰나?

✔ CSS 값에서 숫자만 뽑고 싶을 때

parseInt("20px") // → 20

서버에서 받은 문자열 형태 숫자를 정수로 바꿀 때
사용자가 입력한 숫자 문자열 처리할 때
진수 변환할 때


📌 6. 왜 “parse”라는 단어를 쓰냐?

"parse" = 문자열을 읽어서 의미 있는 구조로 분석하는 것
즉 "123abc" 라는 문자열에서 “123이라는 정수"를 해석해내는 과정이기 때문.


필요하면 parseFloat() / Number() / + 연산자 숫자 변환 차이도 자세히 비교해줄게!

Q. "{\"name\":\"홍길동\",\"age\":20}"

더보기

서버가 보내는 JSON 문자열과,

이를 JS 코드에서 문자열 리터럴로 표현한 모습이 다르게 보이기 때문에 헷갈릴 수 있어.

 

결론부터 말하면:


1. 실제 JSON 문자열은 이렇게 생긴 게 맞다

서버가 보내는 JSON 텍스트:

{"name": "홍길동", "age": 20}

이게 순수한 JSON 문자열이며, 사람이 봐도 자연스럽고 브라우저 네트워크 탭에서도 이렇게 보인다.

이 자체는 그냥 문자열이다.
문자({, }, ", :, ,)로 구성된 텍스트일 뿐.


✅ 2. 그런데 JS 코드 안에서 JSON 문자열을 "문자열 리터럴" 로 표현하려 하면 이렇게 변한다

JS 문자열 안에서는 " 자체자열 끝을 의미하기 때문에 -> 이스케이프(\) 해야 한다.

 

그래서 JS 파일, 콘솔, 코드 속에서 JSON을 문자열로 적으면 이렇게 보인다:

"{"name": "홍길동", "age": 20}"

"
{\"name\":\"홍길동\",\"age\":20}"

여기서 \" 는 “JS 문자열에서 따옴표를 표현하기 위해 이스케이프한 것"이지 JSON의 실제 내용이 아니다.


🔍 즉, 차이는 "표현 방식"의 차이일 뿐

실제 JSON 텍스트:

{"name":"홍길동","age":20}

JavaScript 문자열 리터럴로 JSON 텍스트를 나타낸 모습:

"{\"name\":\"홍길동\",\"age\":20}"

 

두 번째에서 " 앞에 \ 가 들어가는 이유는:

  • JS에서 " " 로 문자열을 감쌀 때
  • 내부 " " 를 그대로 넣으면 문자열이 끝났다고 착각하므로
  • \" 로 "문자를 이스케이프" 해야 한다

🔥 예시 비교

1) 서버 응답(JSON raw)

{"ok":true,"user":"홍길동"}

2) JS에서 변수에 담으면

const jsonText = "{\"ok\":true,\"user\":\"홍길동\"}";

3) 실제로 이걸 JSON.parse 하면

JSON.parse(jsonText) // → { ok: true, user: "홍길동" }

✅ 더 쉽게 말해볼게

✔ 서버가 보내는 건 “순수 문자열” ⇒ 이스케이프 필요 없음

✔ JS 코드에서 문자열로 적을 때는 "문자열 문법" 때문에 이스케이프가 들어감

=> 그래서 \" 가 생기는 것뿐


원하면

  • 문자열 리터럴에서 언제 이스케이프해야 하는지
  • JSON.parse() 동작 과정
    도 자세히 설명해줄게!

Q. 리터럴 / 이스케이프

더보기

좋아, 지금 헷갈리는 건 “리터럴(literal)”“이스케이프(escape)” 라는 개념이야. 차근차근 설명해줄게.


1️⃣ 리터럴(Literal)

정의:

프로그래밍 언어에서 그대로 값을 나타내는 표기를 리터럴이라고 한다.
즉, 변수에 담거나 연산할 때 코드 안에 직접 적힌 값.

예시

42          // 숫자 리터럴
"Hello"     // 문자열 리터럴
true        // 불리언 리터럴
null        // null 리터럴
[1, 2, 3]   // 배열 리터럴
{a:1, b:2}  // 객체 리터럴

즉, 코드 안에서 직접 작성된 값이 바로 리터럴.


2️⃣ 이스케이프(Escape)

정의:

문자열 안에서 특별한 의미를 가진 문자를 문자 그대로 사용하고 싶을 때
앞에 \(백슬래시)를 붙여 “탈출(escape)”시키는 것.

왜 필요한가?

문자열은 기본적으로 큰따옴표 " " 나 작은따옴표 ' ' 로 감싼다.
그 안에 또 같은 따옴표가 들어가면 문자열이 끝났다고 인식해버림.

예시

// ❌ 오류
const str = "He said "Hello" to me";

// ✅ 올바른 방법: 이스케이프
const str = "He said \"Hello\" to me";
console.log(str);  // He said "Hello" to me

3️⃣ 자주 쓰는 이스케이프 문자

이스케이프 의미
\" 큰따옴표 문자 자체
\' 작은따옴표 문자 자체
\\ 백슬래시 문자 자체
\n 줄바꿈(new line)
\t 탭(tab)
\r 캐리지 리턴
\uXXXX 유니코드 문자

4️⃣ JSON과 이스케이프

JSON 문자열을 JS 코드에서 리터럴(JSON 문자열 모양 그대로)로 쓸 때 이스케이프가 필요함.

// 실제 JSON 텍스트 (서버가 보내는 것)
{"name": "홍길동", "age": 20}

// JS 문자열 리터럴로 작성
const jsonText = "{\"name\":\"홍길동\",\"age\":20}";
// 내부 큰따옴표를 \"로 이스케이프

🔥 핵심 정리

  • 리터럴: 코드 안에 직접 적힌 값 자체 (42, "Hello", [1,2,3])
  • 이스케이프: 문자열 안에서 특별 문자를 문자 그대로 쓰고 싶을 때 \ 붙이는 것 (\", \n)

즉, JSON 문자열을 코드 안에 쓰려면 리터럴 안에서 이스케이프를 해주는 거야.


원하면, 내가 JSON 문자열 → JS 문자열 리터럴 → JS 객체 변환 과정을 그림으로 순서대로 보여줄 수도 있어.
그거 보여줄까?

728x90
반응형