예전에 qunit에서 [code review] 받을 때 [Richard Gibson]이 알려준 내용인데 [jsmocktool] 관련해서 개발하다가 갑자기 생각하서 또 잊을까봐 정리한다.
당시 코드에서 regexp 객체에 flags가 있는지 확인하는 방법으로 속성에 접근해서 아래와 같이 사용했다.
1 | return regexp.flags || regexp.toString().match(/[gimuy]*$/)[0]; | cs |
근데 Richard Gibson이 "나는 불필요한 동작을 하지 않기 위해 in연산자를 사용한다"며 in 연산자를 사용하길 바랬다. 첨에 "엇 뭐지?"라는 생각을 했지만, 잠깐 고민해보니 좋은 의견이였다. 그리고 오늘 글을 쓰기 위해 좀 더 조사를 해봤다.
먼저 속성이 있는지 확인하는 방법은 크게 3가지가 있다.
1. 동등 연산자( == ,=== )
1 2 | if(o[k] === undefined){ } | cs |
2. hasOwnProperty 메서드
1 2 | if(o.hasOwnProperty(v)){ } | cs |
3. in 연산자
1 2 | if(v in o){ } | cs |
이 3가지중 어떤게 가장 빠를까? 한번 고민해보고 아래 글을 읽으면 재밌을거라 생각한다.
시점/브라우저 등 여러가지 상황에 따라 다를 수 있는데 V8(크롬)에서 보면 1번이 가장 빠르다. 왜 그런지는 V8 개발자인 [Vyacheslav Egorov]의 설명을 보면 알 수 있다. 요약하면, 1번의 경우는 흔히 얘기하는 hidden class로 특정 offset을 가지고 있고 반복 호출되면 [Inline Cache] 때문에 굉장히 빠르지만, hasOwnProperty와 in 연산자의 경우는 별도의 캐시를 하지 않고 매번 새로 찾기 때문에 느리다. [비교] (이 말은 키값(offset)이 고정되어 있지 않으면 차이가 없다는 말이다. 실제로 로직에서 키 값을 항상 변경해서 사용하면 성능에 크게 차이가 없다.)
하지만, 비교에서 보면 최근에 hasOwnProperty은 [개선]되어서 지금은 hasOwnProperty도 실제로 비슷한 성능을 내고 있으며 [in 연산자] 역시 언젠가 빠를 것 같다.
다시 돌아와서. 지금까지 보면 1번이 여러 상황에서 적절한 것 같은데 왜 Richard Gibson은 `in`연산자를 사용하라고 했을까?
단순 객체에 속성을 확인하는건 1번이 빠를진 몰라도, 일반적으로 FE을 개발할 때 DOM등 브라우저에 있는 native 객체들에 위의 비교문을 많이 사용한다. 그래서 속성을 읽을 때 단순히 값을 반환하는 경우도 있겠지만, 내부적으로 복잡한 연산이 들어가기 때문에 오히려 1번이 가장 느릴 경우가 많다.
예를 들어. 특정 객체에 offsetHeight라는 속성이 있는지 확인한다면, 1번의 경우는 [forced layout]이 발생하여 엄청나게 느리지만, 2번이나 3번의 경우는 속성이 있는지만 확인하기 때문에 불필요한 forced layout이 발생하지 않는다.
이렇게 단순히 자바스크립트 객체의 속성을 확인하는 방법으로 좋을지 모르지만, DOM이나 기타 native 객체들은 2, 3번(주로 3을 선호한다. 이유는 아래에)을 사용하는게 오히려 좀 더 나은 practice라고 생각하며 아마도 Richard Gibson이 이런 의미로 얘기한 것 같다.
당연하지만, getter의 경우도 1번에서는 동작하지만, 2, 3의 경우는 동작하지 않는다. 참고로 hasOwnProperty는 1, 3번 약간은 다르다. hasOwnProperty은 prototype chaining하지 않고 속성을 찾기 때문에 기대했던 생각과 다른 결과를 만날 수 있다. [참고]
요약하면,
단순 오브젝트를 확인하는건 속성에 접근하여 확인하는게 빠르지만, 브라우저의 객체나 DOM은 in/hasOwnProperty가 괜찮은 방법인 것 같다.
ps. Code HighLight을 하기 위해 보통 markup.su/highlighter/ 을 사용했는데 관리를 안하는지 다른 것을 찾아보다가 http://colorscripter.com/ 을 찾았는데 완전 좋네.
참고 URL.
http://stackoverflow.com/questions/21763617/why-is-getting-a-member-faster-than-calling-hasownproperty
https://bugs.chromium.org/p/v8/issues/detail?id=2472#c8
https://bugs.chromium.org/p/v8/issues/detail?id=2743