分享

DOM系列:Attribute和Property

 ipilipala 2018-10-02

這兩天一直在看DOM元素的attributeproperty,簡單讓人暈。從直譯上,我一開始都理解為“屬性”,而且對於我這樣的新手,將兩者混淆在一起,傻傻的分不清楚。後來經過大大們的指點,知道兩者是不同的東西,但兩者之間又有緊密的聯繫。為了能更清晰的整明白兩者的關係與不同,所以把自己理解和蒐集的資料理了一下,希望對新手有所幫助。

Attribute和property形象上的描述

文章開頭也說了,自己對attributeproperty兩者理不清楚,在蒐集兩者差異的時候,看到了Web技術研究所站長對兩者的描述,簡值是絕了,讓初學者一看就易於理解,下面這部分內容直接複製過來了。

attributeproperty都被翻譯成“屬性”,但是它們有著本質上的區別。拿生活中的示例來說,或許對於像我這樣的新手更易於理解。

“桌子上有個蘋果”。attribute僅僅是描述了這個“有蘋果”的事實,而property則是直指那個桌子上的蘋果。這裡的蘋果是一個實體,用attribute來描述只能說明這個事件的事實。它無法準確的描述出具體哪個蘋果在桌子上。再舉個示例 —— “我爸是李剛”。attribute僅僅是描述了“李剛”這個名字,而property則是直接代表“李剛”這個人(一個實體)。叫“李剛”這個名字的人很多,所以attribute無法確切表示。而property則是直指實體的,可以準確描述事物。但也不是說attribute就絕對無法準確表示事物,只是attribute只能用文字描述,所以它要精確描述一個東西的代價是比property高了許多。比如描述“李剛”可以用他的身份證號碼之類的,可是說不定人家的身份證還是偽造的,所以還需要更多的文字描述才能準確的說明一個東西。

那麼既然propertyattribute好,為什麼還需要attribute呢?就說“我爸是李剛”這件事吧,過了這麼多年了也許很多人都忘了。property是保存在記憶(比如計算機的內存memory)中的,雖然一開始很準確,但是無法長期保存。我們經常會把需要長期保存的東西用文字描述下來,這時就需要用到attribute。而且attributeproperty並不衝突,我們經常會翻閱一些舊資料來補充我們漸淡的記憶。

這些就是它們本質上的區別,在程序中我們可以用另外的方式說明它。attribute是標記語言的概念(比如HTML語言),而標記語言本身就是一種文本,所以attribute這種文本描述的性質在標記語言中很容易使用。而property則是保存在內存中,而內存會隨著程序運行結束被釋放,因此變得無法長期儲存。在JavaScript中,DOM對象通常都是多重繼承的。同時繼承了HTML和JavaScript的ObjectObject是完完全全的內存對象,所以使用的是property,而HTML本身就是標記語言,所以使用的是attribute。當這兩個東西被繼承到同一個對象上的時候經常會讓人混淆起來。由於一些attribute是很常用的,比如idclass等,所以DOM把它們映射到property上以方便使用。這樣我們就會遇到一個對象同時具有id這個attributeproperty(由於class是保留字,所以它被映射到property上時變成className)。

雖然被DOM這樣一搞,初學者易於混淆attributeproperty。但上面的比喻,估計有幫助初學者易於理解。但要更清晰的理解,還是有必要通過示例來闡述。接下來,我們回到我們的代碼世界當中。

attribute和property的定義

其實上面的示例描述,對attributeproperty已經定義的非常清晰。如果我們從生活中的示例回到JavaScript的世界中來。

property指的是DOM的property,是元素屬性。DOM中的節點事實上是一個對象,因此,可以添加自定義屬性以及方法。使用對象訪問屬性的方式,可以訪問到DOM節點的每一個property的屬性。比如下面這個input元素:

<input id="name" name="user" class="form-control" myAttr="my-attri" value="w3cplus" data-control="text" />

我們使用.符號來獲取或者重置DOM節點的property

這個時候,我們回過來查看input元素,對應的一些屬性已被重置了,結果如下圖所示:

從上面我們可以發現,對於自定義的attribute,如果通過.符號來獲取,其值是null。同樣的,自定義的property也不會出現在HTML的元素中,只會存在JavaScript中。另外,property的值可以是任何的數據類型,對大小寫也敏感。

attribute是指標籤屬性,也就是HTML元素指定的屬性,比如上面input元素中的idclass之類的。在瀏覽器的控制台中,可以通過attributes獲取元素中所有的attribute。可以通過for循環,將對應的attribute打印出來,比如:

for (let i = 0; i < $0.attributes.length; i++) {
    console.log($0.attributes[i])
}

大家一看瀏覽器打印的結果就一目瞭然了:

從上面的操作結果來看:

attributeproperty的子集。

但不幸的是,瀏覽器並不是這樣理解的。不過至於為什麼,我也說不清楚,就不在這闡述了,以免誤人子弟。

而W3C規範規定propertyattribute的含義卻如下圖所示:

從上圖中可以看出來其分為三個部分:

Standard Attribute:標準屬性(也被稱為固有屬性),比如示例中的idnameclass等DTD、Scheme中定義的標籤屬性。它的特點是,可以通過點方式或getAttribute都可以訪問和重置。比如下圖所操作的結果:

Custom Property:自定義屬性,通過點方式訪問、設置非DTD/Scheme中定義的標籤屬性。它的特點是僅能通過點方式操作屬性。但在HTML的attribute中並無法顯示出來,只能在JavaScript中顯式。

Custom Attribute:自定義特性(顯式特性),直接在HTML標籤元素或者通過getAttribute(或setAttribute)訪問、重置的非DTD/Scheme中定義的標籤屬性。其特點是可以在HTML標籤中顯式聲明自定義特性,比如示例中的myAttr="my-attri"。另外可以通過getAttribute獲取在HTML標籤中設置的特性,以及使用setAttribute重置該特性。

查閱的一些文檔,獲知從IE8開始各大瀏覽器在這方面就遵守W3C標準。

attribute和property概念上的差異

如果僅從attributeproperty兩單詞上直譯過來 —— “屬性”。但為了更易於區分,更喜歡把attribute稱為“特性”,property稱為“屬性”。回到JavaScript的DOM世界中來。先從他們的概念上來做一個簡單的區分。

attribute是HTML標籤上的某個屬性,比如我們常見的idclassvalueonclick等屬性,以及一些自定義的屬性,比如大家熟悉的data-*,甚至像myAttr這樣的自定義屬性。比如:

<input id="name" name="user" class="form-control" myAttr="my-attri" value="w3cplus" data-control="text" />

在瀏覽器開發者工具中,通過properties可以查看到attributes具體的值,其對應的正好是HTML標籤input中的attributes

回過頭來看properties,其主要是JavaScript獲取DOM對象上的屬性值。而且它是作為JavaScript的基本對象。這個節點包括很多property,比如classListclassName之類的。比如下圖:

從上圖中,我們可以看出來,一個JavaScript對象有很多property,該集合名字為propertiesproperties裡面有其他property以及attributes。而attributes裡面有很多attribute,比如上面示例中的input元素中的idclass之類的。

在JavaScript中,DOM的property可以通過.符號或[]來獲取,比如:

而DOM的attributes則可以通過setAttributegetAttributeremoveAttribute來做相應的處理,這個後面我們會做一些相關的介紹。

attributesproperties使用上的差異

通過上面的介紹,估計大家對attributesproperties或多或少有所瞭解了。但在實際的使用上還是略有差異的。我們來看看一些使用場景的差異性。

同樣拿上面的input舉例。在具體操作之前,簡單的回憶和總結一下:

在HTML標籤元素上的attribute,不管是標準的還是自定義的,它都是attributes這個Object的子集,而attributes又是properties的子集。同時,HTML標籤元素上的標準的attribute同時也是DOM的property,它們也是properties的子集。

為了從語義上對其有所差異性的區分,把attribute稱為HTML Attribute,譯為特性,把property稱為DOM Property,譯為屬性

在實際使用的時候,property通過.(或[])來訪問HTML標籤元素上的標準的attribute,也可以通過其來重置其值;但對於自定義的attribute通過.符號獲取的值是undefined,不過可以通過.來重置它,需要注意的是,雖然重置了,但並不會修改HTML標籤中自定義的attribute值,它只會存在JavaScript中。

對於HTML標籤元素中的attribute,不管是標準的,還是自定義的,都可以通過getAttribute來獲取,通過setAttribute來重置,還可以使用removeAttribute來刪除。

先來看通過.符號獲取、重置標準與非標準的attribute。結果如下:

我們再來看getAttributesetAttributeremoveAttribute對HTML標籤的標準(和非標準的)attribute的操作:

通過for循環把操作過的attributes打印出來,看修改後的結果:

上面的小示例再次驗證了:

propertyattribute對HTML標籤的標準的attribute(比如,nameidclass)會相互影響;但property對於HTML標籤的非標準的attribute做的相應修改,不會影響到HTML標籤中的attribute,但會存在JavaScript的DOM中的property

上面的示例,看到的是propertyattribute對HTML標籤原有的標準和非標準的attribute進行的操作。接下來看另一個場景,新增標準和非標準的屬性。先來看property增加屬性:

再來看看attribute增加屬性。使用attribute給HTML標籤增加屬性,使用的是setAttribute方法。比如下圖所示:

使用setAttribute給HTML標籤添加attribute,不管是標準的,還是非標準的都能添加到HTML的標籤中。比如上面的操作,我們通過for循環操作之後,可以看到元素inputattributes中包含了哪些attribute以及其對應的值:

雖然我們通過.符號或者getAttributesetAttribute可以獲取和重置HTML的attribute。而且propertyattribute很多時候能做到一一對應,但有些屬性還是無法相互影響的。比如inputvalue。接下來通過實際示例來闡述。

上圖的結果,我想更易於說明一切。但也還有另我的場景,比如說,用戶在input中輸入了新的值,propertyattribute重新獲取和重置的value將會是什麼樣的結果呢?我把整個過程錄製下來了,大家可以看看其中的差異。

如果上圖不好復原,咱們將上面的過程分步來看。

從上圖的結果來看,用戶在input新輸入值之後,attribute通過getAttribute重新獲取的value值依舊是HTML標籤元素中attribute的值,但property並不一樣,通過.符號獲取的值就是用戶新輸入的值。

再來看第二種情形:

先用property重置inputvalue值,這個時候property.符號重獲的value值是property重置後的值,但attributegetAttribute獲取的還是HTML標籤元素中attribute的值。接著用戶在input中輸入新的值,這個時候再次使用property獲取value的值,從結果上可以看出來,獲取到的是用戶新輸入後的值,但attribute還是依舊不變。

還有一種情況是,先用attributesetAttribute來重置inputvalue值,比如下圖所示:

結果一目瞭然了,propertyattribute獲取的值都是attribute重置後的value值。但用戶在input中輸入新的值,property獲取的是用戶新輸入的值,而attribute還是最初setAttribute設置的value值。

簡單的小結一下:

attributevalue值只在初始化的時候跟property一樣,使用getAttribute獲取的值是初始化的值,如果沒有設置則是空,除非使用setAttribute手動去改變,但這個改變也不會影響到property的值。propertyvalue值是input實時輸入的值,但該值的改變同樣也不會影響attributevalue值。

上面看到的只是其中的一部分,其實還有很多場景也會略有不同。比如input這樣的表單元素中的disabledchecked等屬性,以及元素的hidden屬性。這裡就不再羅列了,感興趣的同學可以自己在瀏覽器的控制台中,像上面這樣一個一個嘗試一下,我想只要你嘗試了一定會很清晰的明白。下面簡單的羅列幾個常見的不同之處:

對於有些標準的特性的操作,element.getAttributeelement.property獲取的值存在差異性。比如hrefsrcvaluestyleonclick等:

  • element.getAttribute獲取的是href的實際值,element.property獲取的是完整的url
  • element.property可以從element.setAttribute獲得同步
  • element.getAttribute不能從element.property獲得同步
  • element.getAttribute只能獲得輸入框的原始值,element.property可以獲取輸入框修改後的值
  • 對於checkbox時,未選中時,element.getAttribute返回的是nullelement.property返回的是false;反之,選中時,element.getAttribute仍返回nullelement.property返回的是true
  • 對於style標籤,element.getAttribute返回的是string,而element.property返回的是object

除了有差異性之外,attributesproperties也有相同之處:

標準DOM的properties(DOM屬性)與attributes(HTML Attribute,即標籤特性)是同步的。公認的attributes會添加到DOM對象property上,比如idstyleclassNamedisabledchecked等。這時候直接操作property(也就是element.checked)或者使用element.getAttribute(或element.setAttribute)效果是一致的。但是參數不一定相同,比如element.classNameelement.getAttribute('class')兩者獲取的元素的class

總結

如果你要是閱讀到這裡的,說明你有足夠多的耐性。花了不少的時間,聽我胡扯許久,但我還是希望上面的內容沒有對你們造成誤解,或者對你們有所幫助。最後再花一點時間稍微總結一下下。

propertyattributies都是properties的子集,而每個attributeattributies的子集。attribute指的是HTML的Attribute,可以理解為HTML的特性,它們可以自定義,可以在HTML標籤元素上添加attribute或者使用setAttribute添加(這兩者添加的方式不一樣,但結果一樣)。大多數情況之下,HTML標籤添加的都是attribute屬性,property則是使用.符號進行更改。通常來講,更自以為是相互影響(但也有不一樣的地方,比如inputvalue)。另外,當添加的是非標準的屬性時,propertyattribute是不互通的。除此之外,一些特殊屬性則需要特殊對待。

在實際應用當中,大部分DOM操作都是使用properties來完成。但有些情形之下,使用attributes更為適合,比如:在自定義HTML的attributes,因為它並不同步到DOM的property。還有就是訪問內置HTML的attributes(設置的初始值),attribute不能從property同步過來,典型的就是前面向大家展示的inputvalue

或許除了上述介紹的之外還有很多遺漏的地方,希望路過的大嬸多多指點。如果你在這方面有更多的經驗,歡迎在下面的評論中分享。要是你覺得文章對你有所幫助,也可以打賞喲(^_^)。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多