原型链上的DOM Attributes

原型链上的DOM Attributes

本文翻译自html5rocks的DOM Attributes now on the prototype chain

Chrome开发小组最近发表声明他们正在將DOM properties移动到原型链中。这个更新将会在Chrome 43(2015年4月发布beta版本)中实现。这可以让Chrome与Web IDL标准以及其他浏览器(IE和Firfox)保持一致。注:旧的基于Webkit的浏览器与标准不兼容但是safari已经与标准兼容了。

注意:本篇文章中Attribute与Property没有区别,并可以互换。ECMA script标准定义了Properties包括Attributes。一个JS property等于一个WebIDL Attribute。本文里面的Attribute并不是HTML Attribute(例如image元素上class)。

这项更新有很多好处:

  • 因为遵循了规范,所以跨浏览器的兼容性更好(IE和Firefox早就与规范保持一致了)
  • 让开发者一致且高效地创建DOM对象上的getter/setter
  • 提高DOM编程的灵活性。例如:你可以更加方便地实现polyfill方案。你可以模拟在某些浏览器中缺失的属性。或者你可以重写DOM属性的行为

例如,假设有一个W3C规范规定的新属性叫做isSuperContentEditable,并且Chrome还没有实现它。但是我们可以实现一个polyfill去模拟这个特性。作为一个库的开发者,很自然地你会想到修改prototype来实现这个属性,这样更加高效。

Object.defineProperty(HTMLDivElement.prototype, "isSuperContentEditable", {
    get: function() { return true; },
    set: function() { /* some logic to set it up */ },
});

在这次更新之前,为了在Chrome中与其他DOM属性保持一致,一定要为每个实例增加新的isSuperContentEditable属性。为页面上的每一个HTMLDivElement实例创建新属性是非常低效的。

这些更新对Web平台的一致性、性能和规范化都很重要。当然这也会带来一些不兼容的问题。如果你以前依赖过Chrome或Webkit的这个特性,强烈建议检查下自己的站点并阅读下面的更新总结。

更新总结

在DOM实例上调用hasOwnProperties现在会返回false

有时开发者会调用hasOwnProperties方法来检查属性是否某个对象上。以后这将不再起作用。因为DOM属性都移动到了原型链中,而hasOwnProperties方法不会检查原型链上是否有这个属性。

在Chrome 42及以前版本中,如下代码的执行结果为true

> div = document.createElement("div");
> div.hasOwnProperty("isContentEditable");
true

在Chrome 43及之后的版本中华,将会返回false

> div = document.createElement("div");
> div.hasOwnProperty("isContentEditable");
false

这意味着如果你想要检查DOM上的isContentEditable属性是否可用,那么需要检查HTMLObject的prototype。例如:HTMLDivElement继承自HTMLElement ,而HTMLElement上定义了isContentEditable属性。

> 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不会序列化prototype上的DOM属性。例如,如果你尝试序列化Push Notication的PushSubscription对象,那么你的代码会受到影响。

Chrome 42及以前的版本下,如下代码可以正常工作:

> JSON.stringify(subscription);
{
    "endpoint": "https://something",
    "subscriptionId": "SomeID"
}

Chrome 43及以后的版本中将不会序列化DOM属性,因为他们定义在prototype上。最后只会返回一个空对象。

> 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及以前的版本中修改只读DOM属性不会抛出异常但也不会生效。

// 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方法来做属性支持与否的检测,来兼容旧的浏览器。那么那个站点的开发者可以做如下事情:

我就是对这个改动感兴趣

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏知无涯

ASP跨站提交参数检测

36316
来自专栏极客猴

Django 学习笔记之模板

本文是自己 Django 学习笔记系列的第四篇原创文章。主要接着篇文章的视图内容,讲解模板的用法。另外也说下 Django 学习笔记系列的安排。自己计划大概 1...

430
来自专栏机器学习从入门到成神

Vue2.0中v-for迭代语法变化(key、index)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinat_35512245/articl...

911
来自专栏梧雨北辰的开发录

iOS面试知识总结之问题解决

凡经历过iOS面试的我们总会发觉,即使实际开发中做过许多项目,也难免为一个普通的面试题受挫。这也许不是因为我们技术不过关,而是因为在平时我们忽略了怎样将用到的知...

3124
来自专栏大内老A

我所理解的Remoting(1):Marshaling & Activation[上篇]

什么是Marshaling &Activation 对任何一项分布式技术(Distributed Technology),比如Remoting,XML Web ...

1918
来自专栏自由而无用的灵魂的碎碎念

Tips in Visual Studio 2008

.NET几乎程序员都在使用visual studio 2008进行开发。可是,你通过它达到最大的开发效率了吗?

1252
来自专栏python3

beautiful soup爬虫初识

官方推荐使用lxml作为解析器,因为效率更高. 在Python2.7.3之前的版本和Python3中3.2.2之前的版本,必须安装lxml或html5lib, ...

1364
来自专栏林德熙的博客

WPF 触摸到事件

在 WPF 界面框架核心就是交互和渲染,触摸是交互的一部分。在 WPF 是需要使用多个线程来做触摸和渲染,触摸是单独一个线程,这个线程就是只获得触摸,而将触摸转...

2932
来自专栏Python小屋

Python爬虫扩展库scrapy选择器用法入门(一)

关于BeutifulSoup4的用法入门请参考Python爬虫扩展库BeautifulSoup4用法精要,scrapy爬虫案例请参考Python使用Scrapy...

3405
来自专栏前端小叙

js粘贴事件paste简单解析及遇到的坑

在用户执行粘贴操作的时候,js能够获得剪切板的内容,本文讨论一下这个问题。 目前只有Chrome支持获取剪切板中的图片数据。还好需要这个功能的产品目前只支...

7106

扫码关注云+社区

领取腾讯云代金券