HTML öznitelikleri (Attributes) ile DOM özellikleri (Properties) arasındaki farklar
(jakearchibald.com)- Aynı öğeye bağlı olsalar bile HTML öznitelikleri ile DOM özellikleri ayrı depolama alanları gibi çalışır; bu yüzden bir taraftaki değişiklik diğer tarafa otomatik olarak yansımayabilir
- Öznitelikler HTML serileştirmesinde ve geliştirici araçlarındaki Elements panelinde görünür, ancak özellikler yalnızca DOM durumu olduğundan
outerHTMLgibi çıktılarda yer almaz - Öznitelik değerleri her zaman string'dir ve adları büyük/küçük harfe duyarlı değildir; buna karşılık özellikler nesne dahil farklı türler alabilir ve adları büyük/küçük harfe duyarlıdır
id,className,htmlFor,ariaLabelgibi öznitelikleri yansıtan özellikler bulunurken,input.valuegibi mevcut durum ile varsayılan ayarın ayrıldığı istisnalar da vardır- Çerçeveler arasında hangi hedefin ayarlandığı değişir: Preact ve VueJS çoğunlukla özellikleri, React çoğunlukla öznitelikleri tercih eder; Lit ise
.valuesözdizimiyle ikisini açıkça ayırır
Öznitelikler ve özellikler aynı adı taşısa da farklı olabilir
- Öznitelikler (attributes) ile özellikler (properties) birbirinden farklı depolama alanları gibi çalışabilir
- `` üzerinde
getAttribute('foo')'bar'döndürürken,div.fooundefinedolabilir - Sonrasında
div.foo = 'hello world'ayarlansa bilefooöznitelik değeri'bar'olarak kalır
- `` üzerinde
- Framework şablonlarında `` gibi öznitelikmiş gibi görünen sözdizimi kullanılsa da, içeride duruma göre özellik ayarlanabilir
- Hangi durumda özellik ayarlanacağı framework'e göre değişir
- Bazı ayarlar hem özelliği hem özniteliği değiştiren yan etkiler oluşturabilir
HTML serileştirmesinde kalan şey özniteliktir
- Öznitelikler hem HTML'de hem DOM'da bulunur, ancak özellikler yalnızca DOM'da vardır
div.setAttribute('foo', 'bar')vediv.hello = 'world'birlikte çalıştırılsa bilediv.outerHTMLiçinde `
` gibi yalnızca öznitelikler görünür
- Tarayıcı geliştirici araçlarındaki Elements paneli öğenin özniteliklerini gösterir; tüm özellikleri göstermez
Değer türü ve büyük/küçük harf davranışı
- Öznitelik değerleri serileştirilmiş biçimde çalışmak zorunda olduğundan her zaman string'dir
- Bir nesne
setAttributeile verilirse"[object Object]"string'i olarak saklanır - Aynı nesne bir özelliğe verilirse nesne türü korunabilir
- Bir nesne
- Öznitelik adları büyük/küçük harfe duyarlı değildir
HeLlO="world"DOM içindehelloözniteliğine normalize edilebilirsetAttribute('FOO', 'bar')dafooözniteliği olarak görünür
- Özellik adları büyük/küçük harfe duyarlıdır
div.TeSt = 'value'ayarlansa bilediv.testundefinedolabilir
- Öznitelik adlarının aksine öznitelik değerleri büyük/küçük harfe duyarlıdır
Özniteliği yansıtan özellikler
- Bazı özellikler belirli bir özniteliği yansıtır (reflect)
div.id,idözniteliğini okuyup yazan bir getter/setter gibi çalışırdiv.id = 'bar'çalıştırıldığındaidözniteliği de'bar'olur
- Yansıtma ilişkisinde veri kaynağı özniteliktir
- Özellik ayarlanırsa öznitelik güncellenir
- Özellik okunursa öznitelik değeri okunur
- Spesifikasyonda tanımlanan öznitelikler için kullanım kolaylığı adına karşılık gelen özellikler çoğu zaman oluşturulur
- Rastgele bir
fooözniteliği spesifikasyonda tanımlı olmadığından, karşılık gelen birfooözelliği otomatik oluşmaz
- Rastgele bir
- `` spesifikasyonu “Content attributes” bölümünde öznitelikleri, “DOM interface” bölümünde ise özellikleri tanımlar
reversedvetypeIDL özellikleri, aynı adlı içerik özniteliklerini reflect etmelidir
Adın değiştiği yansıtma ilişkileri
- Bazı özelliklerin yansıttığı öznitelikle adı farklıdır
- Bazen ad, JavaScript özellik stiline uyması için değişir
- `` üzerindeki
el.crossOrigin,crossoriginözniteliğini yansıtır - Tüm öğelerde
el.ariaLabel,aria-labelözniteliğini yansıtır - ARIA yansıtma özellikleri 2023 sonlarında tarayıcılar arasında ortak destek kazandı; öncesinde yalnızca öznitelik kullanılabiliyordu
- `` üzerindeki
- Bazen de geçmişteki JavaScript rezerve sözcükleri nedeniyle ad değişmiştir
- Tüm öğelerde
el.className,classözniteliğini yansıtır - `` üzerindeki
el.htmlFor,forözniteliğini yansıtır
- Tüm öğelerde
Doğrulama, tür dönüşümü ve varsayılan değerler
- Özelliklerde doğrulama ve varsayılan değerler bulunabilir, ancak özniteliğin kendisinde böyle bir davranış yoktur
input.type, öznitelik ile özellik arasındaki farkı iyi gösteririnput.getAttribute('type')nullolsa bileinput.typevarsayılan değer olarak'text'döndürürinput.type = 'number'hem öznitelikte hem özellikte'number'gibi görünürinput.type = 'foo'özniteliğe'foo'yazar, ama özellik getter'ı geçersiz değeri görüp'text'döndürür
- Bazı özellikler tür dönüşümü yapar
- `` için
details.getAttribute('open')boş string ikendetails.opentrueolur details.open = false,openözniteliğini kaldırırdetails.open = 'hello', string'i doğrudan özniteliğe yazmaz; boolean'a çevirir veopenözniteliğinin mevcut olduğu bir durum oluşturur
- `` için
img.heightgibi özellikler öznitelik değerini sayıya dönüştürür- Setter gelen değeri sayıya çevirir ve negatif değerleri 0 kabul eder
input.value, mevcut değer ile varsayılan değeri ayırır
inputüzerinde hemvalueözelliği hemvalueözniteliği vardır, ancakvalueözelliğivalueözniteliğini yansıtmazvalueözniteliğini yansıtan özellikdefaultValue'durdefaultValuegetter'ıvalueözniteliğini ya da boş string'i döndürürdefaultValuesetter'ıvalueözniteliğini string olarak ayarlar
valueözelliği başlangıçtadefaultValue'yu takip eder, ancak JavaScript veya kullanıcı etkileşimiyle ayarlandıktan sonra iç değeri kullanır- Başlangıçtaki `` içinde
value,defaultValue,getAttribute('value')üçü de'default'değerindedir input.defaultValue = 'new default'çalıştırıldığında öznitelik vevaluebirlikte'new default'gibi görünür- Sonrasında
input.value = 'hello!'çalıştırılırsavalue'hello!'olur, ancak öznitelik iledefaultValue'new default'olarak kalır setAttribute('value', 'another new default')çalıştırılsa bile mevcutvalue'hello!'olarak korunur
- Başlangıçtaki `` içinde
- Form sıfırlandığında iç
valuedurumunun da sıfırlanması bu şekilde çalışabilir
Öznitelikler ayar, özellikler durum için daha doğaldır
- Öznitelikleri ayar (configuration), özellikleri ise durum (state) için kullanmak daha doğal bir ayrımdır
- `` adı hariç bu ayrımı iyi gösteren bir örnektir
valueözniteliği varsayılan değeri ayarlarvalueözelliği mevcut durumu sunar
- Özellik okunup yazılırken doğrulamanın uygulanması, buna karşılık öznitelik okunup yazılırken uygulanmaması da bu yaklaşımla uyumludur
veaçık durumuopenözniteliğiyle ifade eder; tarayıcı kullanıcı etkileşimine göre bu özniteliği doğrudan ekleyip kaldırır- Bu tasarım, özniteliğin ayar için olduğu ayrımını bozar
- DOM yöneten framework'lerin veya sıradan JavaScript kodunun, DOM'un kendi kendine değişebildiği durumlara hazırlıklı olması gerekir
- Alternatif bir tasarım; `` gibi varsayılan ayar özniteliği, mevcut durumu okuyup yazan
details.openözelliği ve durumu hedeflemek için bir CSS sözde sınıfına ayrılabilirdi - Simon Peters bununla ilgili erken tasarım tartışmasını buldu
contenteditablede bu ayrımı bozar, ancak çok sayıda kırılmayı göze alan bir opt-in olarak değerlendirilir
Framework'lere göre işleme biçimi
- Preact ve VueJS, bazı önceden tanımlı istisnalar dışında
propName in elementtrue olduğunda özellik ayarlar; değilse öznitelik ayarlar- Varsayılan olarak öznitelikten çok özelliği tercih ederler
- String tabanlı render yöntemleri bunun tersine çalışır ve yalnızca özelliğe özel girdileri yok sayar
- İlgili uygulamalar: Preact'in
setProperty, VueJS'inshouldSetAsProp
- React, bazı önceden tanımlı istisnalar dışında öznitelik ayarlar
- Bu yaklaşım, string tabanlı render yöntemlerine daha yakın bir mantık üretir
- Custom element özellikleri React'in önceden tanımlı listesinde yer almadığından öznitelik olarak ayarlanır ve yalnızca özelliğe özel API'ler çalışmayabilir
- React 19'da custom element'ler için Preact/VueJS modeline geçilmesi planlanıyor
- React,
classNameadlı özellik adını öznitelik benzeri bir sözdizimiyle yaygınlaştırdı; ancak içerideclassözniteliğini ayarlar - İlgili uygulama: React'in
setProp
- lit-html, öznitelik ile özellik ayrımını sözdiziminde korur
- `` gibi adın başına
.koymak, öznitelik değil özellik ayarlamak anlamına gelir - İlgili dokümantasyon: Lit expressions
- `` gibi adın başına
3 yorum
Hacker News yorumları
data- özniteliklerini* kullanmak, yazıda ele alınan yöntemler arasında makul bir uzlaşma sağlar
Bu öznitelikler JavaScript’te
datasetüzerinde okuma/yazma özellikleri olarak otomatik biçimde açığa çıkar vedocument.getElementById('myDiv').dataset.payload == "something"gibi erişilebilirAncak HTML öznitelikleri
kebab-case, JavaScript isecamelCasekullandığı içindata-my-cool-data-attributedeğerinindataset.myCoolDataAttributeolmasına dikkat etmek gerekircamelCasekullanan çeşitli ekosistemler genelinde büyük harfli kısaltmaların nasıl ele alınacağına dair yerleşik bir teamül yok; bu yüzdendataset.myIDgibi durumlar muğlaklaşıyorkebab-caseilecamelCasedönüşümünden kaçınmak içinElement.hasAttribute('data-thing'),Element.getAttribute('data-thing'),Element.setAttribute('data-thing', '...')gibi metotları kullanıyorumDOM’da inceleme yaparken veya hata ayıklarken tuhaf bir dönüşümden geçmek zorunda kalınmadığı için niyet çok daha net oluyor
Ayrıca https://developer.mozilla.org/en-US/docs/Web/HTML/Global_att... adresinde
data-*küresel öznitelikleri, “betiklerin HTML ile DOM temsili arasında kendilerine özgü bilgileri değiş tokuş etmesini sağlayan özel veri öznitelikleri” olarak açıklanıyorBurada kastedilen bağlamlar mutlaka farklı
iframe’ler değil; tarayıcı eklentilerinde olduğu gibi aynı DOM’a erişen ayrı JavaScript yürütme bağlamları oluşturan durumlarGeliştirici araçları protokolü terminolojisinde bunlara isolated worlds da deniyor
Yazıda ele alınanlar, hayata pek katkısı olmayan karmaşıklık ve davranışları gösteriyor
Bu tür davranışların artısı yok, eksisi var; spesifikasyonun DOM nesneleri ile JavaScript nesnelerini aynı şey olarak tanımlayıp özniteliklerle özellikleri de aynı kavram hâline getirmesi gerekirdi
DOM düğümlerinde string olmayan değerler saklayabilmek bariz bir avantaj ve hafife alınacak bir konu değil
Tüm özelliklerin yalnızca string olabileceği şart koşulmadıkça bu hiç de basit değil
Sayılarla dönüşüm, nesne atanabilen özellikler ve özniteliklerle eşleşmeyen özellikler de hesaba katılmalı
Yine de %100 sabit bir teamül ya da kural olsaydı daha iyi olurdu; ama bu basit bir iş değil
addEventListenergibi metotlar tek tek DOM öğelerinin prototip özellikleridir, ama string öznitelik olarak bakıldığında anlamlı değildirO zaman DOM öğesi metotlarının
HTMLElement.addEventListener(foo, 'some-event', e => console.log(e));gibi serbest fonksiyonlar olması gerekirdi; bu bir zevk meselesi olsa da JavaScript’te nesne metodu çağrısı kullanabilmek daha iyiDOM öğelerinde durumu
setAttributeile değiştiren çok belirli bir arayüz var; bu arayüz üzerinden DOM’a mesaj göndermek için oluşturulmuş JavaScript nesnesine rastgele özellik eklediğinizde bunun neden otomatik olarak yönlendirileceğini beklemek gerektiğini sorguluyorumBöyle bir API daha iyi bir deneyim sunabilir, ama bazı zor sorunları var; yine de daha temiz olacağı kesin
Belki de backend koduyla çok uzun süre uğraştığım içindir; bu tür arayüzlere bakınca içeride tuhaf pek çok şey varmış ve geçmişteki iyi niyetli bir geliştirici mümkün olan en güvenli sarmalayıcıyı vermiş gibi hissediyorum
Anlamaya yardımcı olan bakış açısı, dar anlamdaki özniteliğin bir DOM düğümü, yani
Attrdüğümü olduğudurBu düğüm
name,value,ownerElement,prefixgibi özelliklere sahip olabilir ve bütünüyle, dizi olmayan birNamedNodeMapbiçiminde sahibi olan öğeninattributesözelliğinin değeri olarak erişilebilirBu yüzden
getAttribute(name)adı yanıltıcıdır; gerçekte öznitelik düğümünün kendisini değil, ilgili öznitelik düğümününvalueözelliğini döndürdüğü içingetAttributeValue(name)adına daha yakındırReferans: https://developer.mozilla.org/en-US/docs/Web/API/Element/get..., https://developer.mozilla.org/en-US/docs/Web/API/Element/get..., https://developer.mozilla.org/en-US/docs/Web/API/Attr
setAttribute,getAttribute,getAttributeNames,hasAttributeile yapılamayıp öznitelik düğümleri ya dael.attributesile yapılabilen pratik bir şey var mı bilmiyorumÖznitelik düğümlerini öğeler arasında taşıyamazsınız, bir öğe içinde öznitelik düğümlerinin sırasını da değiştiremezsiniz
Jake, peki buna ne olacak: https://jakearchibald.com/2023/against-self-closing-tags-in-...
Property’yi güncellememek gerektiği yönündeki mantığı anlıyorum, ama CSS ile hedeflenebilmesi kullanışlı
:checked’a benzer şekilde pseudo-class da olması gerektiğini söyledimDebugger’dan geçmektense DOM’u anında kontrol etmek hata ayıklamayı çok daha kolay hale getiriyor
Belki de en önemli fark kalıcılık, ama yazıda buna değinilmiyor
Attribute’lar, sayfadan ayrılmamak gibi o DOM ağacının aynı kök nesnesine erişilebildiği sürece korunur
Nesne property’leri ise yalnızca o nesne garbage collection’a uğrayana kadar korunur
DOM node’u klonlanırsa ya da serialize/deserialize edilirse, aynı attribute’lara sahip tamamen farklı bir DOM node’u olur; bu yüzden diğer node’un varsayılan olmayan property’lerine sahip olmaz
İlginç bir yazı
JavaScript’teki DOM öğelerini hep bir proxy gibi gördüm
Gerçek DOM öğesi üzerinde çalışmanızı sağlıyorlar; ama aynı zamanda sadece JavaScript nesneleri oldukları için, gerçek öğeyle etkileşen fonksiyonları kullanmanın yanında değer atayıp istediğiniz şeyi yapabileceğiniz hissini veriyorlar
Örneklerle iyi açıklanmış olması güzel; özellikle de sık sık gözden kaçabilen birkaç ayrıntı içerdiği için birçok kişiye yardımcı olabilir
DOM property’leri IDL attributes olarak da adlandırılır
Spesifikasyon yazarları dışında
IDL attributesdiyen pek az kişi var; ikisine de attribute denince de çok kafa karıştırıcı oluyorGüzel bir yazı; daha iyi bir ifade biçiminin nasıl görünebileceğini merak ettiriyor
HTML’in string olmayan attribute’lara sahip olabilmesi ve bu değerlerin kapsamı olan bir
scriptetiketindeki yerel değerlere referans verebilmesi ilginç olurduAttribute’ları varsayılan ayarlar olarak görmek biraz tuhaf geldi
Örneğin
classattribute’u yalnızca varsayılan değeri gösterseydi, sınıfları toggle ederken DOM denetçisinde ya da string’e çevrilmiş HTML’de aktif sınıfın görünmemesi veya pasif sınıfın görünmesi gibi epey tuhaf durumlar ortaya çıkardıclassattribute’u bu sistem içinde gayet iyi çalışıyorBelgenin sahibi olarak
classattribute’unu ben ayarlarım ve zaman içinde bu ayarı değiştirebilirim; ama bunu yalnızca ben yaparımAlternatif bir sistemde tarayıcı, hover veya focus durumuna tepki olarak sınıfları kendi kendine ekleyip kaldırırdı; neyse ki bunu yapmıyor ve bunun yerine pseudo-class kullanılıyor
https://emewjin.github.io/html-attribute-dom-property/
attributeilepropertyaynı "özellik" olarak çevrilmiş..