javascript 特性(attribute)與屬性(property)
特性和屬性是javascript中兩個很重要同時也很容易混淆的概念:
特性(attribute) 是DOM構建的一個組成部分
屬性(property) 是元素保持執行時資訊的主要手段,並且可以通過屬性獲取這些執行時資訊
我們可以通過一個簡單的示例來演示特性與屬性的區別:
<html>
<head></head>
<body>
<a id="link" href="./1.html">link</a>
<script>
var link = document.getElementById('link');
var newHref = "./2.html";
link.href = newHref;
console.log(link.href===newHref,link.getAttribute('href')===newHref);
// false true
console.log("attribute:",link.getAttribute('href'));
// attribute: ./2.html
console.log("property:",link.href);
// property: file:///C:/Users/Administrator/Desktop/jquery/2.html
</script>
</body>
</html>
在上述程式碼中,我們建立了一個連結標籤,獲取它的引用,並將它的href屬性修改為一個新值。通過console日誌我們可以看到不管是特性還是屬性都已經被成功修改,但是特性與屬性的值卻是不一樣的。特性的值是我們賦予的,而屬性值則由相對路徑被轉成了絕對路徑。回憶前文關於屬性的定義,屬性是元素保持執行時資訊
1 DOM 特性和 DOM 屬性
在訪問或設定元素的特性值時有兩種方法:使用傳統的 DOM 方法 getAttribute
和 setAttribute
或使用 DOM 物件上與之對應的屬性。
舉例來說,假設一個元素儲存在物件e中,如果我們希望獲取元素的id屬性,可以通過下面兩種方式:
e.getAttribute('id');
e.id;
同樣,不管我們通過下面的哪種方式,都可以修改元素的id值:
e.setAttribute('id','test');
e.id = 'test';
也就是說,設定了特性的值,屬性值會跟著改變,反之亦然。
但是這並不代表特性和屬性共享一個相同的值。特性和對應的屬性雖然有聯絡,但並不總是相同的。
1.1 跨瀏覽器命名
在談到特性和對應的屬性命名時,屬性的名稱在不同的瀏覽器上通常更加一致。如果在一個瀏覽器中,我們能通過一個特定的名稱訪問一個屬性,那麼在其他瀏覽器中,很有可能也可以用同樣的名稱訪問該屬性。屬性命名之間雖然會有一些差異,但是特性和屬性命名之間的差異則會更多。
舉個例子,在大多數瀏覽器中都可以用class獲取到元素的class特性,但是IE中卻需要使用className,並且IE對應的屬性名稱也是className。
1.2 命名限制
特性(attribute),表示為傳遞給 DOM 方法的字串,其命名規範是非常自由的。但屬性名稱,由於可以作為識別符號使用點表示法進行訪問,所以其命名規範是更受限的,屬性名稱必須符合識別符號的規則,而且還有一些保留關鍵字也不能用。
例如,<label>
的for特性是關鍵字,所以在ECMAScript規範中,可以用htmlFor屬性進行表示,同樣的class由className來表示。另外,由多個單片語成的特性名稱由“駝峰式”的屬性名稱來表示,例如,特性readonly的屬性名稱為readOnly。更多差異,參見下表。
特性名稱(Attribute) | 屬性名稱 (Property) |
---|---|
for | htmlFor |
class | className |
readonly | readOnly |
maxlength | className |
class | className |
cellspacing | cellSpacing |
rowspan | rowSpan |
colspan | colSpan |
tabindex | tabIndex |
cellpadding | cellPadding |
usemap | useMap |
frameborder | frameBorder |
contenteditable | contentEditable |
1.3 自定義特性的行為
並不是所有的特性都有元素的屬性來表示。雖然這適用於 HTML DOM 的原生特性,但我們在頁面元素上定義的自定義特性(custom attributes),則不會自動轉換為元素屬性的表達方式。要想訪問這些元素的特性值,需要使用 DOM 方法 getAttribute() 和 setAttribute() 。
如果不確定一個特性的屬性是否存在,可以對其進行測試,如果不存在的話再使用 DOM 方面,參見下面的例子:
let value = element.someValue?element.someValue:
element.getAttribute('someValue');
在 HTML5 中,對所有的自定義特性使用 data-
字首,以便遵守 HTML5 的規範。即便使用的是 HTML4,也同樣建議使用這種方式,以便將標籤適應未來。除此之外,這是分離自定義特性和原生特性一個很好的約定。
1.4 效能注意事項
總的來說,屬性的訪問速度比相應的特性訪問速度要快,特別是在IE瀏覽器中。讓我們來證明一下。
<html>
<head></head>
<body>
<div id="test"></div>
<script>
var count = 5000000;
var element = document.getElementById('test');
var begin ,end, value,n;
begin = new Date();
for(n=0;n<count;n++){
value = element.getAttribute('id');
}
end = new Date();
console.log("getAttribue cost "+(end.getTime()-begin.getTime())+" ms.");
begin = new Date();
for(n=0;n<count;n++){
value = element.id;
}
end = new Date();
console.log("element.id cost "+(end.getTime()-begin.getTime())+" ms.");
begin = new Date();
for(n=0;n<count;n++){
element.setAttribute('id','test');
}
end = new Date();
console.log("setAttribue cost "+(end.getTime()-begin.getTime())+" ms.");
begin = new Date();
for(n=0;n<count;n++){
element.id = 'test';
}
end = new Date();
console.log("write element.id cost "+(end.getTime()-begin.getTime())+" ms.");
</script>
</body>
</html>
下面是不同瀏覽器的執行結果(單位為ms):
瀏覽器 | getAttribute | Property獲取 | setAttribue | Property設定 |
---|---|---|---|---|
chrome 71.0.3578.98 | 288 | 96 | 1715 | 669 |
Firefox 64.0 | 13 | 12 | 746 | 439 |
Edge 17.17134 | 3018 | 2301 | 48125 | 1691 |
IE 11 | 33676 | 16386 | 40683 | 15775 |
可以看出來通過屬性設定或者獲取值的效能明顯優於通過 DOM 方式, IE在這方面的表現尤為突出。