1. 程式人生 > >javascript 特性(attribute)與屬性(property)

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 方法 getAttributesetAttribute 或使用 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在這方面的表現尤為突出。