這兩天一直在看DOM元素的attribute 和property ,簡單讓人暈。從直譯上,我一開始都理解為“屬性”,而且對於我這樣的新手,將兩者混淆在一起,傻傻的分不清楚。後來經過大大們的指點,知道兩者是不同的東西,但兩者之間又有緊密的聯繫。為了能更清晰的整明白兩者的關係與不同,所以把自己理解和蒐集的資料理了一下,希望對新手有所幫助。
Attribute和property形象上的描述
文章開頭也說了,自己對attribute 和property 兩者理不清楚,在蒐集兩者差異的時候,看到了Web技術研究所站長對兩者的描述,簡值是絕了,讓初學者一看就易於理解,下面這部分內容直接複製過來了。
attribute 和property 都被翻譯成“屬性”,但是它們有著本質上的區別。拿生活中的示例來說,或許對於像我這樣的新手更易於理解。
“桌子上有個蘋果”。attribute 僅僅是描述了這個“有蘋果”的事實,而property 則是直指那個桌子上的蘋果。這裡的蘋果是一個實體,用attribute 來描述只能說明這個事件的事實。它無法準確的描述出具體哪個蘋果在桌子上。再舉個示例 —— “我爸是李剛”。attribute 僅僅是描述了“李剛”這個名字,而property 則是直接代表“李剛”這個人(一個實體)。叫“李剛”這個名字的人很多,所以attribute 無法確切表示。而property 則是直指實體的,可以準確描述事物。但也不是說attribute 就絕對無法準確表示事物,只是attribute 只能用文字描述,所以它要精確描述一個東西的代價是比property 高了許多。比如描述“李剛”可以用他的身份證號碼之類的,可是說不定人家的身份證還是偽造的,所以還需要更多的文字描述才能準確的說明一個東西。
那麼既然property 比attribute 好,為什麼還需要attribute 呢?就說“我爸是李剛”這件事吧,過了這麼多年了也許很多人都忘了。property 是保存在記憶(比如計算機的內存memory )中的,雖然一開始很準確,但是無法長期保存。我們經常會把需要長期保存的東西用文字描述下來,這時就需要用到attribute 。而且attribute 和property 並不衝突,我們經常會翻閱一些舊資料來補充我們漸淡的記憶。
這些就是它們本質上的區別,在程序中我們可以用另外的方式說明它。attribute 是標記語言的概念(比如HTML語言),而標記語言本身就是一種文本,所以attribute 這種文本描述的性質在標記語言中很容易使用。而property 則是保存在內存中,而內存會隨著程序運行結束被釋放,因此變得無法長期儲存。在JavaScript中,DOM對象通常都是多重繼承的。同時繼承了HTML和JavaScript的Object 。Object 是完完全全的內存對象,所以使用的是property ,而HTML本身就是標記語言,所以使用的是attribute 。當這兩個東西被繼承到同一個對象上的時候經常會讓人混淆起來。由於一些attribute 是很常用的,比如id 、class 等,所以DOM把它們映射到property 上以方便使用。這樣我們就會遇到一個對象同時具有id 這個attribute 和property (由於class 是保留字,所以它被映射到property 上時變成className )。
雖然被DOM這樣一搞,初學者易於混淆attribute 和property 。但上面的比喻,估計有幫助初學者易於理解。但要更清晰的理解,還是有必要通過示例來闡述。接下來,我們回到我們的代碼世界當中。
attribute和property的定義
其實上面的示例描述,對attribute 和property 已經定義的非常清晰。如果我們從生活中的示例回到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 元素中的id 、class 之類的。在瀏覽器的控制台中,可以通過attributes 獲取元素中所有的attribute 。可以通過for 循環,將對應的attribute 打印出來,比如:
for (let i = 0; i < $0.attributes.length; i++) {
console.log($0.attributes[i])
}
大家一看瀏覽器打印的結果就一目瞭然了:
從上面的操作結果來看:
attribute 是property 的子集。
但不幸的是,瀏覽器並不是這樣理解的。不過至於為什麼,我也說不清楚,就不在這闡述了,以免誤人子弟。
而W3C規範規定property 和attribute 的含義卻如下圖所示:
從上圖中可以看出來其分為三個部分:
Standard Attribute:標準屬性(也被稱為固有屬性),比如示例中的id 、name 、class 等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概念上的差異
如果僅從attribute 和property 兩單詞上直譯過來 —— “屬性”。但為了更易於區分,更喜歡把attribute 稱為“特性”,property 稱為“屬性”。回到JavaScript的DOM世界中來。先從他們的概念上來做一個簡單的區分。
attribute 是HTML標籤上的某個屬性,比如我們常見的id 、class 、value 和onclick 等屬性,以及一些自定義的屬性,比如大家熟悉的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 ,比如classList 、className 之類的。比如下圖:
從上圖中,我們可以看出來,一個JavaScript對象有很多property ,該集合名字為properties ,properties 裡面有其他property 以及attributes 。而attributes 裡面有很多attribute ,比如上面示例中的input 元素中的id 、class 之類的。
在JavaScript中,DOM的property 可以通過. 符號或[] 來獲取,比如:
而DOM的attributes 則可以通過setAttribute 、getAttribute 和removeAttribute 來做相應的處理,這個後面我們會做一些相關的介紹。
attributes 和properties 使用上的差異
通過上面的介紹,估計大家對attributes 和properties 或多或少有所瞭解了。但在實際的使用上還是略有差異的。我們來看看一些使用場景的差異性。
同樣拿上面的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 。結果如下:
我們再來看getAttribute 、setAttribute 和removeAttribute 對HTML標籤的標準(和非標準的)attribute 的操作:
通過for 循環把操作過的attributes 打印出來,看修改後的結果:
上面的小示例再次驗證了:
property 和attribute 對HTML標籤的標準的attribute (比如,name 、id 、class )會相互影響;但property 對於HTML標籤的非標準的attribute 做的相應修改,不會影響到HTML標籤中的attribute ,但會存在JavaScript的DOM中的property 。
上面的示例,看到的是property 和attribute 對HTML標籤原有的標準和非標準的attribute 進行的操作。接下來看另一個場景,新增標準和非標準的屬性。先來看property 增加屬性:
再來看看attribute 增加屬性。使用attribute 給HTML標籤增加屬性,使用的是setAttribute 方法。比如下圖所示:
使用setAttribute 給HTML標籤添加attribute ,不管是標準的,還是非標準的都能添加到HTML的標籤中。比如上面的操作,我們通過for 循環操作之後,可以看到元素input 的attributes 中包含了哪些attribute 以及其對應的值:
雖然我們通過. 符號或者getAttribute 、setAttribute 可以獲取和重置HTML的attribute 。而且property 和attribute 很多時候能做到一一對應,但有些屬性還是無法相互影響的。比如input 的value 。接下來通過實際示例來闡述。
上圖的結果,我想更易於說明一切。但也還有另我的場景,比如說,用戶在input 中輸入了新的值,property 和attribute 重新獲取和重置的value 將會是什麼樣的結果呢?我把整個過程錄製下來了,大家可以看看其中的差異。
如果上圖不好復原,咱們將上面的過程分步來看。
從上圖的結果來看,用戶在input 新輸入值之後,attribute 通過getAttribute 重新獲取的value 值依舊是HTML標籤元素中attribute 的值,但property 並不一樣,通過. 符號獲取的值就是用戶新輸入的值。
再來看第二種情形:
先用property 重置input 的value 值,這個時候property 的. 符號重獲的value 值是property 重置後的值,但attribute 的getAttribute 獲取的還是HTML標籤元素中attribute 的值。接著用戶在input 中輸入新的值,這個時候再次使用property 獲取value 的值,從結果上可以看出來,獲取到的是用戶新輸入後的值,但attribute 還是依舊不變。
還有一種情況是,先用attribute 的setAttribute 來重置input 的value 值,比如下圖所示:
結果一目瞭然了,property 和attribute 獲取的值都是attribute 重置後的value 值。但用戶在input 中輸入新的值,property 獲取的是用戶新輸入的值,而attribute 還是最初setAttribute 設置的value 值。
簡單的小結一下:
attribute 的value 值只在初始化的時候跟property 一樣,使用getAttribute 獲取的值是初始化的值,如果沒有設置則是空,除非使用setAttribute 手動去改變,但這個改變也不會影響到property 的值。property 的value 值是input 實時輸入的值,但該值的改變同樣也不會影響attribute 的value 值。
上面看到的只是其中的一部分,其實還有很多場景也會略有不同。比如input 這樣的表單元素中的disabled 、checked 等屬性,以及元素的hidden 屬性。這裡就不再羅列了,感興趣的同學可以自己在瀏覽器的控制台中,像上面這樣一個一個嘗試一下,我想只要你嘗試了一定會很清晰的明白。下面簡單的羅列幾個常見的不同之處:
對於有些標準的特性的操作,element.getAttribute 和element.property 獲取的值存在差異性。比如href 、src 、value 、style 和onclick 等:
element.getAttribute 獲取的是href 的實際值,element.property 獲取的是完整的url
element.property 可以從element.setAttribute 獲得同步
element.getAttribute 不能從element.property 獲得同步
element.getAttribute 只能獲得輸入框的原始值,element.property 可以獲取輸入框修改後的值
- 對於
checkbox 時,未選中時,element.getAttribute 返回的是null ,element.property 返回的是false ;反之,選中時,element.getAttribute 仍返回null ,element.property 返回的是true
- 對於
style 標籤,element.getAttribute 返回的是string ,而element.property 返回的是object
除了有差異性之外,attributes 和properties 也有相同之處:
標準DOM的properties (DOM屬性)與attributes (HTML Attribute,即標籤特性)是同步的。公認的attributes 會添加到DOM對象property 上,比如id 、style 、className 、disabled 和checked 等。這時候直接操作property (也就是element.checked )或者使用element.getAttribute (或element.setAttribute )效果是一致的。但是參數不一定相同,比如element.className 和element.getAttribute('class') 兩者獲取的元素的class 。
總結
如果你要是閱讀到這裡的,說明你有足夠多的耐性。花了不少的時間,聽我胡扯許久,但我還是希望上面的內容沒有對你們造成誤解,或者對你們有所幫助。最後再花一點時間稍微總結一下下。
property 和attributies 都是properties 的子集,而每個attribute 是attributies 的子集。attribute 指的是HTML的Attribute ,可以理解為HTML的特性,它們可以自定義,可以在HTML標籤元素上添加attribute 或者使用setAttribute 添加(這兩者添加的方式不一樣,但結果一樣)。大多數情況之下,HTML標籤添加的都是attribute 屬性,property 則是使用. 符號進行更改。通常來講,更自以為是相互影響(但也有不一樣的地方,比如input 的value )。另外,當添加的是非標準的屬性時,property 和attribute 是不互通的。除此之外,一些特殊屬性則需要特殊對待。
在實際應用當中,大部分DOM操作都是使用properties 來完成。但有些情形之下,使用attributes 更為適合,比如:在自定義HTML的attributes ,因為它並不同步到DOM的property 。還有就是訪問內置HTML的attributes (設置的初始值),attribute 不能從property 同步過來,典型的就是前面向大家展示的input 的value 。
或許除了上述介紹的之外還有很多遺漏的地方,希望路過的大嬸多多指點。如果你在這方面有更多的經驗,歡迎在下面的評論中分享。要是你覺得文章對你有所幫助,也可以打賞喲(^_^)。
|