자바스크립트에서 같다는 것: ===, Object.is, 객체 동일성
===와 Object.is가 일반 값, 유효한 숫자가 아님을 나타내는 NaN, 부호가 다른 0, 객체를 어떻게 다르게 비교하는지 예측하고 목적에 맞는 규칙을 선택한다.
표준·구현·측정·해석 표시는 무엇인가요?
- 표준웹 표준이나 언어 명세가 정한 동작
- 구현특정 기술이나 브라우저가 실제로 구현한 동작
- 측정명시한 환경에서 직접 실행해 관찰한 결과
- 해석앞선 근거에서 도출한 설계 판단
- 미확인아직 공식 근거나 재현 결과를 확인하지 못한 내용
30초 요약
비교 연산을 고를 때는 “어느 쪽이 더 강한가”보다 어떤 규칙이 필요한가를 먼저 묻는다.
===는 타입을 바꾸지 않고 비교한다. 객체라면 같은 객체 값인지 본다.Object.is는===와 다른 별도 규칙을 사용한다.- 두 규칙의 눈에 띄는 차이는
NaN과+0,-0이다. - 둘 다 객체의 중첩 속성을 하나씩 따라가며 비교하지 않는다.
읽기 전에 되짚을 개념
이 글은 앞 글의 다음 모델을 사용한다.
- 표현식은 값으로 평가된다.
- 객체 표현식을 평가할 때마다 새 객체 값이 만들어진다.
const alias = original처럼 이미 얻은 객체 값을 다른 이름에도 연결할 수 있다.- 두 이름이 같은 객체 값에 연결되어 있으면 한쪽을 통한 속성 변경이 다른 쪽에서도 보인다.
코드에서 // true나 // false는 그 줄의 비교 결과를 적은 주석(comment, 실행되지
않는 설명)이다. NaN은 계산 결과가 유효한 숫자가 아님을 나타내는 특별한 Number
값이고, -0은 음의 부호를 가진 0이다.
같다는 말에는 비교 규칙이 필요하다
일상에서 “같다”는 말은 상황에 따라 뜻이 달라진다.
- 주민등록번호가 같은 사람
- 이름 철자가 같은 사람
- 같은 모양의 두 컵
- 책상 위의 바로 그 컵 하나
코드도 마찬가지다. 사용자 ID가 같은지, 객체가 바로 그 하나인지, 모든 필드가 같은지에 따라 필요한 규칙이 달라진다. 자바스크립트는 하나의 보편적인 “같음” 대신 여러 비교 연산과 내부 비교 관계를 정의한다.
이 글은 그중 ===와 Object.is에 집중한다. ==는 타입 변환 규칙을 포함하는 다른
연산이다. 그 규칙이 필요한 코드를 만날 수 있지만, 이번 글의 결과에 섞어 외우지는
않는다.
일치 비교는 타입부터 확인한다
다음 결과를 먼저 예측한 뒤 주석을 확인해 보자.
1 === 1 // true
1 === '1' // false
true === true // true
true === 1 // false
'안녕' === '안녕' // true
null === null // true
null === undefined // false1 === '1'에서 두 값이 화면에 비슷하게 보여도 하나는 Number, 다른 하나는
String이다. ===는 문자열을 숫자로 변환하지 않고 바로 false로 판단한다.
비교 연산자의 양쪽에 놓인 값을 피연산자라고 부른다.
“===는 값과 타입을 둘 다 비교한다”는 입문용 문장은 대체로 결과를 예측하는 데
도움이 된다. 다만 객체와 특별한 숫자 값까지 설명하려면 명세의 실제 규칙을 한 단계 더
살펴봐야 한다.
객체는 내용이 아니라 같은 객체인지를 비교한다
먼저 객체 표현식의 개수를 세어 보자.
const first = { id: 1 }
const alias = first
const lookalike = { id: 1 }
first === alias // true
first === lookalike // falsefirst와 alias는 같은 객체 값에 연결되어 있다. lookalike는 속성 모양이 같아도
별도의 객체 표현식으로 만들어졌다.
이를 관계로 그리면 결과가 분명해진다.
first ─┐
├── 객체 A { id: 1 }
alias ─┘
lookalike ── 객체 B { id: 1 }배열과 함수도 객체 값이므로 같은 규칙을 따른다.
[] === [] // false
const items = []
const sameItems = items
items === sameItems // true
function firstHandler() {}
function secondHandler() {}
firstHandler === secondHandler // false두 함수의 코드가 똑같아 보여도 서로 다른 두 함수 선언은 각각 별도의 함수 객체를 만든다.
NaN과 부호 있는 0이 두 규칙을 가른다
숫자에서는 두 가지 특별한 결과를 따로 기억해야 한다.
NaN === NaN // false
0 === -0 // trueNaN인지 확인하려고 value === NaN을 쓰면 항상 false다. 이 목적에는
Number.isNaN(value)를 사용한다.
부호 있는 0은 대부분의 산술과 표시에서 같은 0처럼 보이지만 부호가 결과에 영향을 주는 연산도 있다.
1 / 0 // Infinity
1 / -0 // -Infinity모든 비교에서 이 차이가 중요하다는 뜻은 아니다. 다만 비교 규칙을 정확히 설명할 때
+0과 -0을 같은 값으로 처리하는지 구분해야 한다.
Object.is가 사용하는 비교 규칙
앞의 특별한 숫자 예제를 다시 실행하면 차이가 드러난다.
Object.is(NaN, NaN) // true
Object.is(0, -0) // false
Object.is(1, 1) // true
Object.is(1, '1') // false
Object.is('a', 'a') // true그래서 Object.is를 단순히 “===보다 더 엄격한 연산”이라고 부르면 충분하지 않다.
NaN에서는 ===가 false, Object.is가 true이므로 한 방향의 강약 관계로
설명하기 어렵다. 두 규칙이 특별한 숫자를 다르게 취급한다고 이해한다.
Object.is도 객체의 내용을 비교하지 않는다
메서드 이름에 Object가 들어가지만 객체 속성을 깊게 검사하는 기능은 아니다.
const first = { profile: { name: '민지' } }
const alias = first
const lookalike = { profile: { name: '민지' } }
Object.is(first, alias) // true
Object.is(first, lookalike) // false객체 피연산자에서는 Object.is와 ===가 모두 같은 객체인지 판단한다. 중첩 깊이나
속성 개수는 비교하지 않는다.
데이터 내용이 같은지 판단하려면 먼저 제품에서 말하는 “같음”을 정해야 한다.
function isSameUser(left, right) {
return left.id === right.id
}return은 오른쪽의 비교 결과를 함수의 결과로 호출한 곳에 돌려준다.
이 함수는 사용자 ID만 같으면 같은 사용자라고 판단한다. 이름이나 설정까지 모두 같아야 하는 제품이라면 비교할 필드가 달라진다. 범용 깊은 비교 도구를 사용하더라도 날짜처럼 별도 규칙이 필요한 값, 연결이 자기 자신으로 돌아오는 구조, 비교에서 제외할 필드를 어떻게 다룰지는 여전히 정해야 한다.
React에서는 다음 상태를 Object.is로 비교한다
React의 useState는 컴포넌트가 렌더링 사이에 값을 기억하게 하는 함수다. 이 함수가
제공하는 상태 설정 함수에 다음 상태를 전달하면 React는 이전 상태와 다음 상태를
비교한다.
먼저 React를 빼고 객체 비교만 확인해 보자.
const previousProfile = { name: '민지' }
const nextProfile = previousProfile
nextProfile.name = '서준'
Object.is(previousProfile, nextProfile) // true속성 값은 달라졌지만 두 이름이 읽는 객체는 여전히 하나다. Object.is는 객체 속성을
펼쳐 보지 않으므로 true다.
React에서 profile이 현재 상태이고 setProfile이 상태 설정 함수라고 가정하면 다음
코드에도 같은 비교 결과가 적용된다.
profile.name = '서준'
setProfile(profile)첫 줄은 React가 관리하던 이전 렌더링의 객체까지 직접 변경하고, 두 번째 줄은 이전과 구별되는 새 객체를 제공하지 못한다. 객체 내용을 자동으로 깊게 비교할 것이라고 기대하면 화면과 객체의 실제 값이 어긋나기 쉽다. 기존 객체를 보존하면서 새 객체를 만드는 방법은 세 번째 글에서 다룬다.
비교 결과를 표로 정리한다
| 왼쪽 | 오른쪽 | === | Object.is | 이유 |
| --- | --- | --- | --- | --- |
| 1 | 1 | true | true | 같은 Number 값 |
| 1 | "1" | false | false | 타입이 다름 |
| NaN | NaN | false | true | 특별한 Number 규칙이 다름 |
| +0 | -0 | true | false | 부호 있는 0 규칙이 다름 |
| 객체 A | 같은 객체 A | true | true | 같은 객체 값 |
| 객체 A | 모양이 같은 객체 B | false | false | 서로 다른 객체 값 |
표의 마지막 두 행이 객체 코드의 핵심이다. 비교 연산자가 객체 내용을 자동으로 복사하거나 펼쳐 보지 않는다.
목적에 맞는 비교를 고른다
실전에서는 다음 질문을 순서대로 묻는다.
- 타입 변환을 원하지 않는 일반적인 값 비교인가? 우선
===를 검토한다. NaN과 부호 있는 0의 SameValue 규칙이 필요한가?Object.is를 검토한다.- 두 변수가 바로 그 하나의 객체를 공유하는지 묻는가? 둘 다 객체에서 같은 결과를 낸다.
- 서로 다른 객체의 데이터 내용이 같은지 묻는가? 제품의 기준에 맞는 필드 비교를 정의한다.
세 번째 글에서는 이 객체 동일성이 왜 불변 업데이트와 React에서 관리하는 상태에 중요한 신호가 되는지 살펴본다.
Active recall
기억에서 꺼내 보기
답을 쓰지 않아도 됩니다. 먼저 머릿속으로 답한 뒤 펼쳐서 정답·이유·흔한 오해를 비교하세요.
01`1 === "1"`은 왜 false일까?
정답
두 값의 타입이 Number와 String으로 다르며, 일치 비교는 타입 변환 없이 서로 다른 타입을 같지 않다고 판단한다.
관련 설명 다시 읽기왜 그런가
숫자처럼 보이는 문자열을 숫자로 자동 변환한 뒤 비교하는 연산이 아니다.
선택한 상태와 다음 복습일은 이 브라우저에만 저장됩니다.
02`{ id: 1 } === { id: 1 }`은 왜 false일까?
정답
객체 표현식을 두 번 평가해 서로 다른 객체 값을 만들었기 때문이다.
관련 설명 다시 읽기왜 그런가
===는 중첩 속성까지 하나씩 따라가며 비교하지 않고 두 값이 같은 객체인지 확인한다.
선택한 상태와 다음 복습일은 이 브라우저에만 저장됩니다.
03`NaN`과 부호 있는 0에서 ===와 Object.is의 결과는 어떻게 다를까?
정답
`NaN === NaN`은 false지만 `Object.is(NaN, NaN)`은 true다. `0 === -0`은 true지만 `Object.is(0, -0)`은 false다.
관련 설명 다시 읽기왜 그런가
두 연산은 숫자에서 서로 다른 비교 관계를 사용한다.
선택한 상태와 다음 복습일은 이 브라우저에만 저장됩니다.
04Object.is는 객체의 모든 중첩 속성을 비교하는 깊은 비교일까?
정답
아니다. 객체에서는 ===와 마찬가지로 같은 객체 값인지 비교한다.
관련 설명 다시 읽기왜 그런가
데이터 내용이 같은지를 판단하려면 제품에서 정한 기준에 맞는 필드 비교나 명시적인 깊은 비교 절차가 필요하다.
선택한 상태와 다음 복습일은 이 브라우저에만 저장됩니다.
05React 객체 상태의 속성을 직접 바꾼 뒤 같은 객체를 상태 설정 함수에 전달하면 `Object.is`의 결과와 화면 갱신은 어떻게 될까?
정답
이전 상태와 다음 상태가 같은 객체이므로 `Object.is`는 true다. React는 이전과 같은 상태를 전달받은 것으로 판단해 그 상태 변경 요청을 화면 갱신에 반영하지 않는다.
관련 설명 다시 읽기왜 그런가
Object.is는 객체 속성을 깊게 검사하지 않는다. 객체 상태를 갱신할 때는 기존 객체를 바꾸지 않고 새 객체를 전달해야 한다.
선택한 상태와 다음 복습일은 이 브라우저에만 저장됩니다.
출처와 검증 범위
아래 날짜는 링크를 마지막으로 열어 본 날입니다. 문서 상단의 검증일은 글의 설명과 적용 범위를 다시 확인한 날입니다.
- IsStrictlyEqualEcma International · 표준 명세 · 확인 2026-07-27
- SameValueEcma International · 표준 명세 · 확인 2026-07-27
- SameValueNonNumberEcma International · 표준 명세 · 확인 2026-07-27
- Object.isEcma International · 표준 명세 · 확인 2026-07-27
- Equality comparisons and samenessMDN Web Docs · 공식 문서 · 확인 2026-07-27
- useStateReact · 공식 문서 · 확인 2026-07-27