翻譯自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的更新就到這裡結束了,如果大家對我翻譯的這篇文章如果有任何疑問,歡迎提意見。