Why is document.all falsy?

John Doe ·

1025 Views

ECMAScript 사양에 따르면 Boolean 형식으로 출력했을 때 true 또는 false를 반환하는 기준을 다음과 같이 정의한다.

 

 

특정객체가 undefined / null 이면 false를 반환

object면 true를 반환 이런식이다.

document.all 의 경우

console.log(typeof document.all);

이렇게 type을 확인해보면 undefined가 찍힌다.

따라서 document.all 은 false 다.

그런데 단순히 아래코드의 결과를 보면

console.log(document.all);

HTMLAllCollection 즉 object가 나오는데 왜 false가 될까?

답은 아래에 있다.

The Document interface's read-only all property returns an HTMLAllCollection rooted at the document node. In other words, it returns all of the document's elements, accessible by order (like an array) and by ID (like a regular object).

 

이곳에 보면

document.all is the only falsy object accessible to JavaScript, because it has the [[IsHTMLDDA]] internal slot.

이런 문구가 있는데, document.all 은 JavaScript에서 액세스할 수 있는 유일한 false 객체라고 한다.

 

일단 document.all 은 과거 브라우저(ie 등)에서 쓰였던 웹표준에 어긋나는 코딩방식이다.

ECMAScript edition 5 를 제창할 당시 요구사항들을 보면

* all 특성은 모든 html 요소와 일치하는 문서 노드에 뿌리를 둔 HTMLAllCollection을 반환해야 한다.

- "all" 에 대해 반환된 개체에는 몇 가지 비정상적인 동작이 있다.

* 사용자 에이전트(브라우저)는 all 객체를 JavaScript의 boolean 연산을 했을 때 false 값으로 변환하는 것처럼 작동해야 한다.

* 사용자 에이전트는 JavaScript에서 == 및 != 연산자를 사용했을 때 all 객체가 마치 정의되지 않은 값과 동일한 것처럼 작동해야 한다.

* 사용자 에이전트는 JavaScript의 typeof 연산자가 all 객체에 적용될 때에 문자열 'undefined'를 반환하도록 작동해야 한다.

이러한 요구 사항들은 작성 당시(ECMAScript 버전 5) 현재 JavaScript 사양을 고의적으로 위반한 것이다.

JavaScript 사양에는 ToBoolean() 연산자가 모든 객체를 참 값으로 변환해야 하며 특정 연산자의 목적을 위해 정의되지 않은 것처럼 작동하는 객체에 대한 조항은 없다. 이러한 위반은 레거시 콘텐츠의 두 클래스와의 호환성에 대한 요구에 의해 발생했다.

1. 레거시 사용자 에이전트를 감지하는 방법으로 document.all을 사용하고

2. 다른 하나는 특정 요소의 존재 여부를 먼저 테스트하지 않고. 해당 레거시 사용자 에이전트만 지원하고 document.all 객체를 사용하는 경우이다.

예제코드를 보면

if (document.all) {
  // 과거 ie같은 브라우저에서 사용
} else if (document.getElementById) {
  // 최신 브라우저에서 사용
}

기본적으로 오랫동안 document.all은 이러한 방식으로 오래된 브라우저를 감지하는 데 사용되었다. 하지만 document.all 을 먼저 검사하기 때문에 두 속성을 모두 제공하는 최신 브라우저는 여전히 document.all 경로안에 있게 된다. 최신 브라우저에서는 물론 document.getElementById를 사용하는 것을 선호하지만 대부분의 브라우저에는 여전히 이전 버전과의 호환성을 위해 document.all이 있기 때문에 document.all이 true이면 else 문은 실행되지 않게 된다.

그래서 코드를 아래처럼 바꾸어야 한다.

if (document.getElementById) {
  // "최신" 브라우저용 `document.getElementById`를 사용하는 코드
} else if (document.all) {
  // 과거 ie같은 브라우저용 `document.all`을 사용하는 코드
}

하지만 많은 기존 코드는 아직 그 반대다.

이 문제에 대한 가장 간단한 수정방법은 document.all을 여전히 쓸 수 있는 최신 브라우저에서 단순히 document.all을 "false" 로 만드는 것이다.

요약하면

1. 최신 브라우저에서도 document.all 을 이용하여 html 요소객체에 접근이 가능하다.

2. 하지만 위와 같은 코드로 기존버전/최신버전 브라우저를 구분하는 데에는 한계가 있을수 있고 일일이 수정을 해주어야 한다.

3. 따라서 if (document.all) 으로 검사했을 때에는 단순히 document.all 을 false로 반환함과 동시에,

document.all 자체를 요소객체에 접근하는 목적으로도 사용할 수 있도록 object (객체) 로 만들었다.

 

Ref.​

document.all is a non-primitive object in the DOM that is falsy. For example, this code doesn't do anything: if (document.all) { alert("hello"); } Can someone explain why this is?

 

html javascript