A equipe do Chrome anunciou recentemente que estamos movendo propriedades DOM para a cadeia de protótipos. Com essa mudança, implementada no Chrome 43 (versão Beta a partir de meados de abril de 2015), o Chrome agora está mais de acordo com as especificações da Web IDL e as implementações de outros navegadores, como o IE e o Firefox. Edição: esclarecido que navegadores mais antigos baseados no WebKit não são compatíveis com a especificação, mas o Safari é agora.
O novo comportamento é positivo de várias maneiras. Ele:
- Melhora a compatibilidade na Web (o IE e o Firefox já fazem isso) por meio da conformidade com a especificação.
- Permite criar getters/setters de maneira consistente e eficiente em cada objeto DOM.
- Aumenta a invasão da programação DOM. Por exemplo, ela permitirá que você implemente polyfills para emular de maneira eficiente a funcionalidade ausente em alguns navegadores e bibliotecas JavaScript que substituem os comportamentos padrão do atributo DOM.
Por exemplo, uma especificação hipotética do W3C inclui uma nova funcionalidade chamada isSuperContentEditable
. Ela não é implementada pelo navegador Chrome, mas é possível "polyfill" ou emular o recurso com uma biblioteca. Como desenvolvedor da biblioteca, use prototype
da seguinte maneira para criar um polyfill eficiente:
Object.defineProperty(HTMLDivElement.prototype, "isSuperContentEditable", {
get: function() { return true; },
set: function() { /* some logic to set it up */ },
});
Antes dessa mudança, para fins de consistência com outras propriedades DOM no Chrome, era necessário criar a nova propriedade em todas as instâncias, o que seria muito ineficiente para cada HTMLDivElement
na página.
Essas alterações são importantes para a consistência, o desempenho e a padronização da plataforma Web, mas podem causar alguns problemas para os desenvolvedores. Se você estava confiando nesse comportamento por causa da compatibilidade legada entre o Chrome e o WebKit, recomendamos verificar seu site e ver o resumo das mudanças abaixo.
Resumo das mudanças
O uso de hasOwnProperty
em uma instância de objeto DOM agora retorna false
.
Às vezes, os desenvolvedores usam hasOwnProperty
para verificar a presença de uma propriedade em um objeto. Isso não vai mais funcionar de acordo com a especificação, porque os atributos DOM agora fazem parte da cadeia de protótipo, e o hasOwnProperty
inspeciona apenas os objetos atuais para ver se estão definidos nele
Antes do Chrome 42, e incluindo, o seguinte retornava true
.
> div = document.createElement("div");
> div.hasOwnProperty("isContentEditable");
true
No Chrome 43 em diante, ela retornará false
.
> div = document.createElement("div");
> div.hasOwnProperty("isContentEditable");
false
Isso significa que, se você quiser conferir se o isContentEditable
está disponível no elemento, será necessário verificar o protótipo no objeto HTMLElement. Por exemplo, HTMLDivElement
herda de HTMLElement
, que define a propriedade isContentEditable
.
> HTMLElement.prototype.hasOwnProperty("isContentEditable");
true
Você não é obrigado a usar o hasOwnProperty
. Recomendamos usar o operando in
, que é muito mais simples, porque vai verificar a propriedade em toda a cadeia de protótipos.
if("isContentEditable" in div) {
// We have support!!
}
Object.getOwnPropertyDescriptor na instância de objeto DOM não retornará mais um descritor de propriedade para atributos.
Caso seu site precise do descritor de propriedade de um atributo em um objeto DOM, você precisa seguir a cadeia de protótipos.
Para conseguir a descrição da propriedade no Chrome 42 e versões anteriores, faça o seguinte:
> Object.getOwnPropertyDescriptor(div, "isContentEditable");
Object {value: "", writable: true, enumerable: true, configurable: true}
O Chrome 43 em diante vai retornar undefined
nessa situação.
> Object.getOwnPropertyDescriptor(div, "isContentEditable");
undefined
Para receber o descritor de propriedade da propriedade isContentEditable
, siga a cadeia de protótipos da seguinte maneira:
> Object.getOwnPropertyDescriptor(HTMLElement.prototype, "isContentEditable");
Object {get: function, set: function, enumerable: false, configurable: false}
O JSON.stringify não vai mais serializar atributos DOM
O JSON.stringify
não serializa propriedades do DOM que estão no protótipo. Por exemplo, isso poderá afetar seu site se você estiver tentando serializar um objeto como PushSubscription de notificações push.
No Chrome 42 e anteriores, o seguinte teria funcionado:
> JSON.stringify(subscription);
{
"endpoint": "https://something",
"subscriptionId": "SomeID"
}
A partir do Chrome 43, as propriedades definidas no protótipo não serão serializadas, e você receberá um objeto vazio.
> JSON.stringify(subscription);
{}
Será necessário fornecer seu próprio método de serialização. Por exemplo, você pode fazer o seguinte:
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);
Gravar em propriedades somente leitura no modo restrito vai gerar um erro
A gravação em propriedades somente leitura precisa gerar uma exceção quando você está usando o modo restrito. Por exemplo, veja o seguinte:
function foo() {
"use strict";
var d = document.createElement("div");
console.log(d.isContentEditable);
d.isContentEditable = 1;
console.log(d.isContentEditable);
}
No Chrome 42 e nas versões anteriores, a função continuaria e continuaria silenciosamente executando a função, embora isContentEditable
não tivesse sido modificado.
// Chrome 42 and earlier behavior
> foo();
false // isContentEditable
false // isContentEditable (after writing to read-only property)
Agora, no Chrome 43 em diante, haverá uma exceção.
// Chrome 43 and onwards behavior
> foo();
false
Uncaught TypeError: Cannot set property isContentEditable of #<HTMLElement> which has only a getter
Estou com um problema. O que devo fazer?
Siga as orientações ou deixe um comentário abaixo e vamos conversar.
Encontrei um site com um problema. O que devo fazer?
Ótima pergunta. A maioria dos problemas com sites é baseada no fato de um site ter escolhido fazer a detecção de presença de atributo com o método getOwnProperty
. Isso é feito principalmente quando o proprietário de um site segmenta apenas navegadores WebKit mais antigos. Existem algumas coisas que um desenvolvedor pode fazer:
- Registre um problema sobre o site afetado no nosso Issue Tracker (Chrome)
- Registre um problema no radar do WebKit e mencione https://bugs.webkit.org/show_bug.cgi?id=49739
Tenho interesse geral em acompanhar essa mudança
- Bug original de 2010: https://bugs.chromium.org/p/chromium/issues/detail?id=43394. Observação: grande parte do trabalho é executado.
- Análise de código para confirmação