专栏首页前端小作坊原型链上的DOM Attributes

原型链上的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 条评论
登录 后参与评论

相关文章

  • 网页上的复制与剪切

    IE 10及以上的版本修改了Document.execCommand()方法,增加了对剪切和复制的支持。Chrome从43版本开始也支持了这项特性。

    mmzhou
  • GA源代码里的小技巧之Beacon请求

    GA监控脚本一般都放在开发者的网页上。域名往往和Google不一样,这样发送请求到Google服务器的时候会涉及到跨域。普通的Ajax请求是做不到的,通常称这种...

    mmzhou
  • ECMAScript 6之WeakMap

    ECMAScript 6中加入了很多新的特性,其中有一个有用的API:WeakMap。Nicholas的博文做了详细的介绍。这也是一篇关于WeakMap的笔记。

    mmzhou
  • Unity 水、流体、波纹基础系列(一)——纹理变形(Texture Distortion )

    如果液体不动时,在视觉上是无法与固体区分开的。你看的到底是水,果冻还是玻璃杯呢?水池是结冰的吗?但可以肯定的是,如果干扰它并观察它是否会变形,以及变形多少就可以...

    放牛的星星
  • 笔记——apk打包的内部流程(六)

    紫兮木溪
  • 死磕 java并发包之AtomicInteger源码分析

    AtomicInteger是java并发包下面提供的原子类,主要操作的是int类型的整型,通过调用底层Unsafe的CAS等方法实现原子操作。

    彤哥
  • 安永:区块链技术带来机遇还是威胁?

    概要 区块链技术(有时被称作分布式账簿技术)目前是资产服务业领导层日程中的优先项。尽管该技术仍处于发展的初期阶段,但由于其具有简化和加速业务流程、保护数据完整...

    点滴科技资讯
  • Spring Boot 在localhost域奇怪的404问题(Mac book pro)

    在mac系统中,明明url是对的,浏览器也可以打开,一个简单的代码调用就是404,你有没有遇到过?

    pollyduan
  • 一斤代码深入理解系列(七):微信小程序中使用微信风格样式库-WeUI

    WeUI 是一套同微信原生视觉体验一致的基础样式库,由微信官方设计团队为微信内网页和微信小程序量身设计,令用户的使用感知更加统一。包含button、cell、d...

    极乐君
  • java之instanceof操作符

    绝命生

扫码关注云+社区

领取腾讯云代金券