前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >原型链上的DOM Attributes

原型链上的DOM Attributes

作者头像
mmzhou
发布2018-08-01 18:50:23
7220
发布2018-08-01 18:50:23
举报
文章被收录于专栏:前端小作坊

原型链上的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来实现这个属性,这样更加高效。

代码语言:javascript
复制
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

代码语言:javascript
复制
> div = document.createElement("div");
> div.hasOwnProperty("isContentEditable");
true

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

代码语言:javascript
复制
> div = document.createElement("div");
> div.hasOwnProperty("isContentEditable");
false

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

代码语言:javascript
复制
> HTMLElement.prototype.hasOwnProperty("isContentEditable");
true

你也不一定要用hasOwnProperty。我们推荐更为简单的in操作符,它会检查整个原型链。

代码语言:javascript
复制
if("isContentEditable" in div) {
    // We have support!!
}

DOM实例上调用Object.getOwnPropertyDescriptor方法不再会返回属性的描述对象

如果你的站点需要获取DOM实例上的属性描述对象,那么你就需要在原型链中获取了。

在Chrome 42及以前的版本中获取属性描述对象可以这么做:

代码语言:javascript
复制
> Object.getOwnPropertyDescriptor(div, "isContentEditable");
Object {value: "", writable: true, enumerable: true, configurable: true}

Chrome 43及以后的版本中就只会返回undefined

代码语言:javascript
复制
> Object.getOwnPropertyDescriptor(div, "isContentEditable");
undefined

这意味着如果你想要获取isContentEditable属性的描述对象,那就需要循着原型链溯流而上找:

代码语言:javascript
复制
> 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及以前的版本下,如下代码可以正常工作:

代码语言:javascript
复制
> JSON.stringify(subscription);
{
    "endpoint": "https://something",
    "subscriptionId": "SomeID"
}

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

代码语言:javascript
复制
> JSON.stringify(subscription);
{}

你必须要提供你的自己的序列化方法,举个例子:

代码语言:javascript
复制
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);

在严格模式中修改只读属性将会抛出错误

在严格模式中修改只读属性应该会抛出异常。看如下样例:

代码语言:javascript
复制
function foo() {
    "use strict";
    var d = document.createElement("div");
    console.log(d.isContentEditable);
    d.isContentEditable = 1;
    console.log(d.isContentEditable);
}

Chrome 42及以前的版本中修改只读DOM属性不会抛出异常但也不会生效。

代码语言:javascript
复制
// Chrome 42 and earlier behavior
> foo();
false // isContentEditable
false // isContentEditable (after writing to read-only property)

在Chrome 43及以后版本中会抛出一个异常。

代码语言:javascript
复制
// Chrome 43 and onwards behavior
> foo();
false
Uncaught TypeError: Cannot set property isContentEditable of #<HTMLElement> which has only a getter

我有个问题,我该怎么做?

遵循本文的指导来修改现有代码,或者留下评论与我讨论。

我见过一个站点有类似的问题,我该怎么做?

好问题,大多数问题都是因为站点需要使用getOwnProperty方法来做属性支持与否的检测,来兼容旧的浏览器。那么那个站点的开发者可以做如下事情:

我就是对这个改动感兴趣

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 原型链上的DOM Attributes
    • 更新总结
      • 在DOM实例上调用hasOwnProperties现在会返回false
      • DOM实例上调用Object.getOwnPropertyDescriptor方法不再会返回属性的描述对象
      • JSON.stringify不再会序列化DOM属性
      • 在严格模式中修改只读属性将会抛出错误
    • 我有个问题,我该怎么做?
      • 我见过一个站点有类似的问题,我该怎么做?
        • 我就是对这个改动感兴趣
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档