-
[JS] JavaScript 메서드를 설계 관점에서 파헤쳐보자.Javascript 2025. 4. 7. 21:29
Object.keys()는 되는데, 왜 obj.keys()는 안 되는 걸까?
우아한테크코스에서는 레벨이 끝날 때마다 레벨 인터뷰라는 시스템을 진행합니다.
일종의 회고이자 모의 면접 같은 시간인데, 이 과정에서 시지프 코치가 제게 흥미로운 질문을 하나 던졌습니다.
“조금 심화적인 질문일 수 있는데요. Object.keys()나 Object.create()는 바로 호출하는데, 왜 Array 관련 메서드는 Array.prototype.filter처럼 호출할까요? Object 메서드들은 static 메서드인 걸까요? JS의 설계 관점에서 생각해보면 좋을 것 같아요.”
이 질문에 선뜻 대답하지 못했고, 저는 그 순간 JavaScript에 대한 깊은 이해가 부족하다는 걸 느꼈습니다. 그래서 이 글을 통해 그 이유를 스스로 정리해보고자 합니다.
1. 자바스크립트의 프로토타입 체이닝
자바스크립트는 프로토타입 기반의 객체지향 언어입니다. 모든 객체는 자신의 부모 역할을 하는 프로토타입 객체를 갖고 있고, 이 연결고리를 통해 필요한 메서드를 찾습니다. 이를 프로토타입 체이닝이라고 하죠.
const arr = [1, 2, 3]; arr.filter(num => num > 1); // → arr → Array.prototype.filter
우리가 arr.filter()라고 쓸 수 있는 이유는 Array.prototype에 filter라는 메서드가 정의되어 있기 때문입니다.
이처럼 배열 인스턴스들은 자신들의 프로토타입에 정의된 메서드에 접근할 수 있습니다.
2. 프로토타입 체인의 최상위는 Object
모든 객체의 프로토타입 체인을 따라가다 보면 결국 Object.prototype에 도달합니다.
그리고 Object.prototype은 더 이상 부모가 없는, 프로토타입 체인의 최상단 객체입니다.
즉, 아래와 같은 구조로 생각해볼 수 있죠.
Object → null Array → Object → null Function → Object → null Date → Object → null
3. 그렇다면 Object.prototype.values가 존재한다면?
만약 우리가 흔히 쓰는 Object.values(obj)를 인스턴스 메서드로 만들 수 있다면 좋겠죠?
const obj = { a: 1 }; obj.values(); // => [1] 이 되면 얼마나 직관적일까?
하지만 여기서 문제가 발생합니다. 예를 들어 Object.prototype.values를 정의하게 되면, 이 메서드는 모든 객체의 조상인 Object.prototype에 존재하게 됩니다.
그 말은 즉,new Date().values(); // ??? (10).values(); // ??? false.values(); // ???
이런 식으로 원시값을 포함한 거의 모든 값이 .values() 메서드를 사용할 수 있게 되어버립니다. 이것은 설계 상 명확하지 않은 동작을 유발할 수 있으며, JS의 일관성도 해칠 수 있습니다.
4. 그래서 객체 관련 메서드는 'static 메서드'처럼 보이는 것이다
이러한 이유로 JavaScript는 Object 관련 메서드들을 모두 생성자 함수에 직접 정의해두었습니다.
Object.keys(obj); Object.values(obj); Object.freeze(obj); Object.create(proto);
이 메서드들은 일종의 static 메서드처럼 동작하지만, 사실 ES5 시절에는 클래스가 없었기에 그냥 Object 함수에 직접 붙은 메서드일 뿐이었죠.
결국 이 설계는 "불필요한 오염을 막기 위한 프로토타입 체이닝의 고려"라고 볼 수 있습니다.
5. 반면 Array는 괜찮은 이유는?
Array.prototype.filter, map, reduce 등의 메서드는 배열 인스턴스에만 필요한 기능입니다. 그래서 이들은 Array.prototype에 정의되어 있어도 문제없습니다.
[1, 2, 3].filter(fn); // 가능 'abc'.filter(fn); // 불가능 (문자열에는 filter가 없음)
문자열, 숫자, 불리언 등의 값은 Array.prototype과 아무 관계가 없기 때문에, 이 메서드들이 불필요하게 확장되는 일은 없습니다.
결론
- Object.keys()는 왜 obj.keys()가 아닌가? → Object.prototype에 메서드를 넣으면 모든 값에서 호출 가능해지기 때문!
- 그래서 Object 관련 메서드는 모두 정적(static) 메서드처럼 설계되었다.
- Array.prototype은 배열 전용 메서드만 포함하고 있기 때문에, 인스턴스 메서드로 제공해도 문제 없음.
출처: 코어자바스크립트
'Javascript' 카테고리의 다른 글
[JS] 바닐라 js로 useState를 만들어 보자 (0) 2025.03.23 [JS] 클래스 상속과 프로토타입 체이닝 (0) 2025.03.02 [JS] 클래스 문법을 비스무리하게 구현해보자 (0) 2025.02.23 [JS] 콜백지옥에서 벗어나기 (5) 2024.06.02 NOW SOPT 자바스크립트 과제 중 타입이 string이었던 이슈 (3) 2024.05.12