翻译自DOM Attributes now on the prototype chain
不过文章中的有一些部分确实难以理解,如果有大神能看出我这里出错了,请及时的告诉我,谢谢
Chrome团队最近宣布我们将DOM属性移动到了原型链上。这个变化将会应用到在Chrome 43上。
这些新的行为将会在以下一个方面带来好处,如下:
- 提高兼容性,IE和Firefox已经遵循了标准
- 允许你一贯并且高效的在DOM对象上创建getter或setter
- 可以提高程序的hack的能力。例如,他允许你用一些兼容性工具,用来高效的模拟在一些浏览器上丢失的功能。并且javascript库也可以重写默认的DOM属性。
例如,假设W3C规范包括一些新的功能,叫做isSuperContentEditable
,Chrome浏览器并没有采用它,但是它可以通过ployfill或者用一些库来模仿新的功能。作为一个库的开发人员,你可能自然的想去使用prototype
去模仿新的功能。
js
Object.defineProperty(HTMLDivElement.prototype, "isSuperContentEditable", { get: function() { return true; }, set: function() { /* some logic to set it up */ }, });
在更新之前,为了保证chrome中和其他DOM元素属性的一致性,你不得不创建一个新的属性在每一个实例上,这将会给页面中的每一个HTMLDivElement
加上那个属性,这是非常低效的。
这次更新为了一致性、高性能和标准化的web平台来说是非常重要的。然而你也可以发起一些issues给开发者。如果你信赖这种因为这是chrome和webkit的遗产,我们鼓励你去检查一下你的网站,并且看一下之后的内容。
更新概要
现在使用
hasOwnProperty
在一个DOM元素上将会返回false
有时候开发者就会使用hasOwnProperty
去检查是否一个属性在一个对象上。现在将不会像之前的那样。因为DOM属性现在是原型链的一部分,并且hasOwnProperty
仅仅检查当前的对象是否定义了它。
在Chrome 42 中下面将会返回true
js
> div = document.createElement("div"); > div.hasOwnProperty("isContentEditable"); true
在Chrome 43中前面的将会返回false
> div = document.createElement("div");
> div.hasOwnProperty("isContentEditable");
false
这个现在意思着如果你想要检查isContentEditable
是否在元素上可用,你需要检查html元素对象的原型上。
假设,HTMLDivElement
继承自HTMLElement
。并且HTMLElement
定义了isContentEditable
属性
js
> HTMLElement.prototype.hasOwnProperty("isContentEditable"); true
你不必一定要使用hasOwnProperty
。我们推荐去使用非常简单的in
操作符。就像下面这个代码去检查是否一个属性在整个原型链中存在。
js
if("isContentEditable" in div) { // We have support!! }
Object.getOwnPropertyDescript
在DOM实例上将不再返回对这个属性的描述
如果你的网站需要获得属性的描述符在一个DOM对象上,你现在需要在原型链上进行操作。
如果你想要获得属性的描述符在Chrome 42 或者更早,你可以这样做
> Object.getOwnPropertyDescriptor(div, "isContentEditable");
Object {value: "", writable: true, enumerable: true, configurable: true}
在Chrome 43中将会返回 undefined
在这断代码中
> Object.getOwnPropertyDescriptor(div, "isContentEditable");
undefined
这将意味着,想要获得属性的描述符,你需要在原型链上进行操作,如下:
> Object.getOwnPropertyDescriptor(HTMLElement.prototype, "isContentEditable");
Object {get: function, set: function, enumerable: false, configurable: false}
JSON.stringify
将不再序列化DOM属性
JSON.stringify
不会序列化DOM在原型上的属性。
例如,这个将会影响你的网站如果你尝试去序列化一个推送提醒对象 PushSubscription
Chrome 43 或者更早的版本,将会按照下面的结果返回
> 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 43 或者更早版本,函数将会继续的执行,并且不会抛出任何异常,尽管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
Chrome 43 关于DOM的更新就到这里结束了,如果大家对我翻译的这篇文章如果有任何疑问,欢迎提意见。