Javascript: hasOwnProperty 쓰는 이유 :: 마이구미
이 글은 자바스크립트 객체의 네이티브 메소드 중 하나인 hasOwnProperty 를 다룬다.
간혹 코드에서 사용하는 모습을 경험했을 것이다.
언제 써야하는지? 왜 쓰는지? 에 의문을 가지고 있다면 이 글을 읽어보길 바란다.
MDN - https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty
우선 hasOwnProperty 메소드가 하는 일은 객체가 특정 프로퍼티에 대한 소유 여부를 반환한다.
const obj = { a: 1 }; obj.hasOwnProperty("a"); // true obj.hasOwnProperty("b"); // false
해당 객체에 특정 프로퍼티가 존재하면 true, 그렇지 않으면 false 를 반환한다.
단, 프로토타입 체인은 확인하지 않고, 해당 객체가 스스로 정의한 프로퍼티만을 판단한다.
자세한 의미는 다음 코드를 통해 확인할 수 있다.
obj.b = 2; Object.prototype.c = 3; obj.b; // 2 obj.c; // 3 obj.hasOwnProperty("b"); // true obj.hasOwnProperty("c"); // false
해당 객체자신의 프로퍼티의 여부를 확인할 때, 조건문을 통해 굉장히 유용하게 사용할 수 있으리라 판단된다.
이번에는 루프 안에서 hasOwnProperty를 사용하는 코드를 확인해보자.
const obj = { a: 1, b: 2, c: 3 }; const copy = {};
let sum = 0; for (let key in obj) { if (obj.hasOwnProperty(key)) { sum += copy[key] = obj[key] * 2;
} }
sum => 2 + 4 + 6 = 12
단순히 객체의 프로퍼티의 값을 2를 곱한 후, 새로운 객체에 할당하는 코드이다.
위 예제에서는 왜 hasOwnProperty 를 사용했을까?
사실 안써도 무방하고 오류도 발생하지 않는다.
그러니 hasOwnProperty 관련 코드를 제거하겠다.
그리고는 만약 사용하지 않는다고 이유를 설명해야한다면, 다음과 같은 근거로 말할 수 있다.
"나는 프로토타입 체인을 통해 추가적인 프로퍼티를 만들지 않았고, 추후에도 그럴 예정이 없어. 확실해"
본인 스스로 확신하는 경우일지라도, 정말 아무도 모르는 일이다.
시간이 지나 코드를 변경해야할 수도 있고, 누군가 자신의 코드를 재사용할 수 도 있다.
하나의 예로 hasOwnProperty 를 사용하지 않은 채, 시간이 흘러 누군가 코드를 수정했다고 가정해보자.
Object.prototype.toText = function() {...}
Object 의 프로토타입에 toText 라는 함수를 추가했다.
그렇다면, 원래의 코드의 결과는 어떻게 될까?
for (let key in obj) { sum += copy[key] = obj[key] * 2; }
sum => NaN
sum 의 결과는 NaN 을 출력한다.
그 이유는 for...in 문법은 열거가능한 프로퍼티를 반복한다.
단, hasOwnProperty 와 달리 프로토타입도 접근한다.
그렇기에 key 를 출력해보면 다음과 같이 출력된다.
a
b
c
toText
겉으로는 안전한 코드일지라도, 미래를 대비하지 못하는 코드이다.
마치 습관처럼 사용을 권장하는 것이 대부분의 의견이다.
이와 같은 일이 발생하지 않기 위해서는 스스로 가정하면 안된다.
즉, 코드의 실행 환경 또는 prototype 접근 및 확장 여부와 같은 것들을 스스로 가정하면 안된다.
또한, hasOwnProperty 사용은 가독성 또한 향상시켜준다.
이 코드는 프로토타입의 체인을 고려하지 않고, 본연 그대로의 객체의 프로퍼티만을 고려한다는 것을 암시할 수 있다.
또 하나의 예제를 통해 말하고자하는 것을 확실히 이해해보자.
const me = { firstName: "Lee", lastName: "JungHyun" }; let text = "The author name is "; 원하는 결과 => The author name is LeeJungHyun
예제는 변수 text 와 객체 me 의 프로퍼티의 값들을 합친 결과를 얻고 싶다고 가정한다.
이를 위해 다음과 같이 코드를 추가할 수 있다.
const me = { firstName: "Lee", lastName: "JungHyun", toText() { return this.firstName + this.lastName; } }; text + me.toText();
하지만 조금 더 간결하게 표현하고 싶어, 시스템적으로 암시적으로 호출되는 toString() 을 활용할 수 있다.
즉, toString() 을 오버라이딩해서 사용할 수 있다.
const me = { firstName: "Lee", lastName: "JungHyun", toString() { return this.firstName + this.lastName; } }; let text = "The author name is "; text + me; // The author name is LeeJungHyun
위와 같은 코드가 존재할 때, toString() 을 오버라이딩 했다는 것을 코드를 통해 명시적으로 알려주는 것이 좋다.
if (me.toString) { text += me; }
위와 같이 조건을 줄 수 있겠지만, 명확하지않다.
왜냐하면 me 객체에 toString() 여부와 상관없이 프로토타입 체인을 통해 접근하기 때문이다.
const me = { firstName: "Lee", lastName: "JungHyun", toString() { return this.firstName + this.lastName; } }; let text = "The author name is "; // Bad - 프로토타입 체인을 통해 Object.toString 접근 if (me.toString) { text += me; } // Good - 직접 정의 or 오버라이딩한 프로퍼티가 있는지 확인 if (me.hasOwnProperty("toString")) { text += me; }
이와 같이 hasOwnProperty 를 사용함으로써, 많은 의미를 담을 수 있게 된다.
결과적으로 hasOwnProperty 사용 이유는 크게 2가지로 나타낼 수 있다.
- 예기치 못한 상황에 따른 버그 대비
- 코드의 가독성 향상