Chrome팀은 최근 DOM 속성을 프로토타입 체인으로 이동한다고 발표했습니다. Chrome 43(2015년 4월 중순 기준 베타)에서 구현된 이 변경사항은 Chrome을 Web IDL 사양 및 IE 및 Firefox와 같은 다른 브라우저 구현에 더 적합하게 만듭니다. 수정: 명확히 했습니다. 이전 WebKit 기반 브라우저는 현재 사양과 호환되지 않지만 이제 Safari는 호환됩니다.
새로운 동작은 여러 가지로 긍정적입니다. 담고 있습니다.
- 사양을 준수하여 웹 전반의 호환성을 개선합니다 (IE 및 Firefox에서는 이미 이 작업을 실행함).
- 모든 DOM 객체에서 일관되고 효율적으로 getter/setter를 만들 수 있습니다.
- DOM 프로그래밍의 해킹 가능성을 높입니다. 예를 들어 기본 DOM 속성 동작을 재정의하는 일부 브라우저 및 JavaScript 라이브러리에서 누락된 기능을 효율적으로 에뮬레이션할 수 있는 polyfill을 구현할 수 있습니다.
예를 들어 가상의 W3C 사양에는 isSuperContentEditable
라는 새로운 기능이 포함되어 있고 Chrome 브라우저는 이를 구현하지 않지만 라이브러리로 이 기능을 '폴리필'하거나 에뮬레이션할 수 있습니다. 라이브러리 개발자는 다음과 같이 prototype
를 사용하여 효율적인 폴리필을 만드는 것이 좋습니다.
Object.defineProperty(HTMLDivElement.prototype, "isSuperContentEditable", {
get: function() { return true; },
set: function() { /* some logic to set it up */ },
});
이번 변경사항 이전에는 Chrome의 다른 DOM 속성과 일관성을 유지하기 위해 모든 인스턴스에서 새 속성을 만들어야 했으며, 이는 페이지의 모든 HTMLDivElement
에 대해 매우 비효율적입니다.
이러한 변경사항은 웹 플랫폼의 일관성, 성능, 표준화에 중요하지만 개발자에게는 몇 가지 문제가 발생할 수 있습니다. Chrome과 WebKit 간의 기존 호환성 때문에 이 동작을 사용하고 있다면 사이트를 확인하고 아래의 변경사항 요약을 참고하시기 바랍니다.
변경사항 요약
이제 DOM 객체 인스턴스에서 hasOwnProperty
를 사용하면 false
이 반환됩니다.
개발자가 hasOwnProperty
를 사용하여 객체에 속성이 있는지 확인하는 경우가 있습니다. 이제 DOM 속성이 프로토타입 체인의 일부가 되고 hasOwnProperty
는 현재 객체를 검사하여 정의되어 있는지만 확인하기 때문에 사양에 따라 더 이상 작동하지 않습니다.
Chrome 42 이전 및 Chrome 42를 포함하여 다음은 true
를 반환합니다.
> div = document.createElement("div");
> div.hasOwnProperty("isContentEditable");
true
Chrome 43 이상에서는 false
을 반환합니다.
> div = document.createElement("div");
> div.hasOwnProperty("isContentEditable");
false
즉, 요소에서 isContentEditable
를 사용할 수 있는지 확인하려면 HTMLElement 객체에서 프로토타입을 확인해야 합니다. 예를 들어 HTMLDivElement
는 isContentEditable
속성을 정의하는 HTMLElement
에서 상속합니다.
> HTMLElement.prototype.hasOwnProperty("isContentEditable");
true
hasOwnProperty
를 사용해야 하는 것은 아닙니다. 전체 프로토타입 체인의 속성을 확인하는 훨씬 간단한 in
연산자를 사용하는 것이 좋습니다.
if("isContentEditable" in div) {
// We have support!!
}
DOM 객체 인스턴스의 Object.getOwnPropertyDescriptor가 더 이상 속성의 속성 설명자를 반환하지 않음
사이트에서 DOM 객체의 속성에 대한 속성 설명자를 가져와야 하는 경우 이제 프로토타입 체인을 따라야 합니다.
Chrome 42 이하에서 속성 설명을 가져오려면 다음을 실행해야 했습니다.
> Object.getOwnPropertyDescriptor(div, "isContentEditable");
Object {value: "", writable: true, enumerable: true, configurable: true}
Chrome 43 이상에서는 이 시나리오에서 undefined
을 반환합니다.
> Object.getOwnPropertyDescriptor(div, "isContentEditable");
undefined
즉, 이제 isContentEditable
속성의 속성 설명어를 가져오려면 다음과 같이 프로토타입 체인을 따라야 합니다.
> Object.getOwnPropertyDescriptor(HTMLElement.prototype, "isContentEditable");
Object {get: function, set: function, enumerable: false, configurable: false}
JSON.stringify가 더 이상 DOM 속성을 직렬화하지 않음
JSON.stringify
는 프로토타입에 있는 DOM 속성을 직렬화하지 않습니다. 예를 들어 푸시 알림의 PushSubscription과 같은 객체를 직렬화하려고 할 때 사이트에 영향을 줄 수 있습니다.
Chrome 42 이하에서는 다음이 작동합니다.
> JSON.stringify(subscription);
{
"endpoint": "https://something",
"subscriptionId": "SomeID"
}
Chrome 43 이상에서는 프로토타입에 정의된 속성을 직렬화하지 않으므로 빈 객체가 반환됩니다.
> JSON.stringify(subscription);
{}
자체 직렬화 메서드를 제공해야 합니다. 예를 들어 다음과 같이 할 수 있습니다.
function stringifyDOMObject(object)
{
function deepCopy(src) {
if (typeof src != "object")
return src;
var dst = Array.isArray(src) ? [] : {};
for (var property in src) {
dst[property] = deepCopy(src[property]);
}
return dst;
}
return JSON.stringify(deepCopy(object));
}
var s = stringifyDOMObject(domObject);
엄격 모드에서 읽기 전용 속성에 쓰면 오류가 발생함
엄격 모드를 사용하는 경우 읽기 전용 속성에 쓰면 예외가 발생해야 합니다. 예를 들어 다음을 살펴보겠습니다.
function foo() {
"use strict";
var d = document.createElement("div");
console.log(d.isContentEditable);
d.isContentEditable = 1;
console.log(d.isContentEditable);
}
Chrome 42 이하에서는 isContentEditable
가 변경되지 않았더라도 함수가 계속 실행되었을 것입니다.
// Chrome 42 and earlier behavior
> foo();
false // isContentEditable
false // isContentEditable (after writing to read-only property)
이제 Chrome 43 이상에서는 예외가 발생합니다.
// Chrome 43 and onwards behavior
> foo();
false
Uncaught TypeError: Cannot set property isContentEditable of #<HTMLElement> which has only a getter
문제가 있습니다. 어떻게 해야 하나요?
안내를 따르거나 아래에 댓글을 남겨주세요.
문제가 있는 사이트를 발견했습니다. 어떻게 해야 하나요?
좋은 질문이에요. 사이트의 대부분의 문제는 사이트에서 getOwnProperty
메서드로 속성 존재 감지를 선택했다는 사실에 기반합니다. 이는 대부분 사이트 소유자가 이전 WebKit 브라우저만 타겟팅한 경우에 발생합니다. 개발자는 다음과 같은 조치를 취할 수 있습니다.
- Chrome의 문제 추적기에서 영향을 받는 사이트에 관한 문제를 신고합니다.
- WebKit 레이더에서 문제를 신고하고 https://bugs.webkit.org/show_bug.cgi?id=49739를 참조합니다.
이 변경사항에 관심이 있음
- 2010년의 원래 버그: https://bugs.chromium.org/p/chromium/issues/detail?id=43394 - 참고: 대부분의 작업이 완료되었습니다.
- 커밋에 대한 코드 검토