6 पॉइंट द्वारा GN⁺ 2024-04-27 | 3 टिप्पणियां | WhatsApp पर शेयर करें
  • एक ही element से जुड़े होने पर भी HTML attributes और DOM properties अलग-अलग storage space की तरह काम करते हैं, इसलिए एक में किया गया बदलाव अपने-आप दूसरे में reflect न हो सकता है
  • attributes HTML serialization और developer tools के Elements panel में दिखते हैं, लेकिन properties सिर्फ DOM की state होती हैं, इसलिए outerHTML जैसे results में नहीं दिखतीं
  • attribute values हमेशा strings होती हैं और names case-sensitive नहीं होते, जबकि properties के पास objects समेत कई तरह के types हो सकते हैं और उनके names case-sensitive होते हैं
  • id, className, htmlFor, ariaLabel जैसे attributes को reflect करने वाली properties होती हैं, जबकि input.value जैसे cases में current state और default setting अलग होती हैं
  • framework के हिसाब से target अलग होता है: Preact और VueJS आम तौर पर properties को, React आम तौर पर attributes को priority देता है, और Lit .value syntax से दोनों को explicitly अलग करता है

Attributes और properties का नाम समान हो, फिर भी वे अलग हो सकते हैं

  • attributes और properties अलग-अलग storage space की तरह काम कर सकते हैं
    • `` में getAttribute('foo') 'bar' return करता है, लेकिन div.foo undefined हो सकता है
    • बाद में div.foo = 'hello world' set करने पर भी foo attribute value 'bar' ही रहती है
  • framework templates में `` जैसी attribute जैसी दिखने वाली syntax इस्तेमाल करने पर भी, internally कुछ cases में property set हो सकती है
    • property कब set की जाती है, यह framework के हिसाब से अलग होता है
    • कुछ settings property और attribute दोनों को बदलने वाला side effect बना सकती हैं

HTML serialization में attributes ही रहते हैं

  • attributes HTML और DOM दोनों में मौजूद होते हैं, लेकिन properties सिर्फ DOM में मौजूद होती हैं
  • div.setAttribute('foo', 'bar') और div.hello = 'world' दोनों run करने पर भी div.outerHTML में `

` की तरह सिर्फ attributes दिखते हैं

  • browser developer tools का Elements panel element के attributes दिखाता है, सभी properties नहीं दिखाता

Value type और case handling

  • attribute values serialized format में काम करनी होती हैं, इसलिए वे हमेशा strings होती हैं
    • object को setAttribute से डालने पर वह string "[object Object]" के रूप में store होता है
    • वही object property में डालने पर object type वैसा ही बना रह सकता है
  • attribute names case-sensitive नहीं होते
    • HeLlO="world" DOM में hello attribute के रूप में normalize हो सकता है
    • setAttribute('FOO', 'bar') भी foo attribute के रूप में दिखता है
  • property names case-sensitive होते हैं
    • div.TeSt = 'value' set करने पर भी div.test undefined हो सकता है
  • attribute names के विपरीत, attribute values case-sensitive होती हैं

Attributes को reflect करने वाली properties

  • कुछ properties किसी खास attribute को reflect करती हैं
    • div.id id attribute को पढ़ने और लिखने वाले getter/setter की तरह काम करता है
    • div.id = 'bar' run करने पर id attribute भी 'bar' में बदल जाता है
  • reflection relationship में attribute data का source होता है
    • property set करने पर attribute update होता है
    • property read करने पर attribute value read होती है
  • specification में defined attributes के लिए सुविधा के तौर पर corresponding property अक्सर बनाई जाती है
    • arbitrary foo attribute spec में defined attribute नहीं है, इसलिए corresponding foo property अपने-आप नहीं बनती
  • `` specification “Content attributes” में attributes और “DOM interface” में properties define करता है
    • reversed और type IDL attributes को उसी नाम के content attributes को reflect करना चाहिए

Reflection relationship में नाम बदल जाना

  • कुछ properties का नाम उस attribute से अलग होता है जिसे वे reflect करती हैं
  • JavaScript property style से match करने के लिए नाम बदलने के cases होते हैं
    • `` का el.crossOrigin, crossorigin attribute को reflect करता है
    • सभी elements का el.ariaLabel, aria-label attribute को reflect करता है
    • ARIA reflection properties 2023 के अंत में cross-browser बनीं; उससे पहले केवल attributes इस्तेमाल किए जा सकते थे
  • पुराने JavaScript reserved words की वजह से भी नाम बदलने के cases हैं
    • सभी elements का el.className, class attribute को reflect करता है
    • `` का el.htmlFor, for attribute को reflect करता है

Validation, type conversion, default values

  • properties के साथ validation और default values जुड़ सकते हैं, लेकिन attributes में खुद ऐसा behavior नहीं होता
  • input.type attribute और property के फर्क को अच्छी तरह दिखाता है
    • input.getAttribute('type') null हो तब भी input.type default value 'text' return करता है
    • input.type = 'number' attributes और properties दोनों में 'number' जैसा दिखता है
    • input.type = 'foo' attribute में 'foo' डालता है, लेकिन property getter invalid value देखकर 'text' return करता है
  • कुछ properties type conversion करती हैं
    • `` में details.getAttribute('open') empty string होता है और details.open true होता है
    • details.open = false open attribute को remove कर देता है
    • details.open = 'hello' string को सीधे attribute में नहीं डालता, बल्कि boolean में convert करके ऐसी state बना देता है जिसमें open attribute मौजूद होता है
  • img.height जैसी properties attribute value को number में convert करती हैं
    • setter incoming value को number में बदलता है, और negative values को 0 के रूप में handle करता है

input.value current value और default value को अलग करता है

  • input में value property और value attribute दोनों होते हैं, लेकिन value property value attribute को reflect नहीं करती
  • value attribute को reflect करने वाली property defaultValue है
    • defaultValue getter value attribute या empty string return करता है
    • defaultValue setter value attribute को string के रूप में set करता है
  • value property शुरुआत में defaultValue को follow करती है, लेकिन JavaScript या user interaction से set होने के बाद internal value इस्तेमाल करती है
    • शुरुआती `` में value, defaultValue, getAttribute('value') सभी 'default' होते हैं
    • input.defaultValue = 'new default' run करने पर attribute और value दोनों 'new default' जैसे दिखते हैं
    • इसके बाद input.value = 'hello!' run करने पर value 'hello!' हो जाता है, लेकिन attribute और defaultValue 'new default' ही रहते हैं
    • setAttribute('value', 'another new default') run करने पर भी current value 'hello!' ही रहता है
  • form reset होने पर internal value state initialize होने के तरीके से काम कर सकती है

Attributes settings के लिए और properties state के लिए ज्यादा natural हैं

  • attributes को configuration के लिए और properties को state के लिए इस्तेमाल करना natural distinction है
  • `` नाम को छोड़ दें तो इस distinction से match करने वाला example है
    • value attribute default value set करता है
    • value property current state provide करती है
  • property read या write करते समय validation apply होना, और attribute read या write करते समय validation apply न होना भी इसी approach से match करता है
  • और open state को open attribute से express करते हैं, और browser user interaction के हिसाब से इस attribute को सीधे add या remove करता है
    • यह design attributes को settings के लिए मानने वाले distinction को तोड़ता है
    • DOM maintain करने वाले frameworks या सामान्य JavaScript code को ऐसी स्थिति के लिए तैयार रहना पड़ता है जिसमें DOM खुद बदलता है
  • alternative design को `` जैसे default setting attribute, current state read/write करने वाली details.open property, और state targeting के लिए CSS pseudo-class में बांटा जा सकता है
  • Simon Peters ने इससे जुड़ी early design discussion ढूंढ निकाली
  • contenteditable भी इस distinction को तोड़ता है, लेकिन इसे कई breakages को accept करने वाले opt-in के रूप में treat किया जाता है

Frameworks के हिसाब से handling

  • Preact और VueJS कुछ predefined exceptions को छोड़कर propName in element true होने पर property set करते हैं, और नहीं तो attribute set करते हैं
    • by default वे attributes से ज्यादा properties को prefer करते हैं
    • string rendering methods उल्टा काम करते हैं, और property-only items को ignore करते हैं
    • related implementations: Preact का setProperty, VueJS का shouldSetAsProp
  • React कुछ predefined exceptions को छोड़कर attribute set करता है
    • यह approach string rendering methods जैसी logic बनाता है
    • custom elements की properties React की predefined list में नहीं होतीं, इसलिए वे attributes के रूप में set होती हैं, और property-only APIs काम न कर सकती हैं
    • React 19 में custom elements के लिए Preact/VueJS model पर switch होने की योजना है
    • React ने className नाम की property को attribute जैसी दिखने वाली syntax के रूप में popular किया, लेकिन internally class attribute set करता है
    • related implementation: React का setProp
  • lit-html syntax में attributes और properties का फर्क बनाए रखता है
    • `` की तरह name के आगे . लगाने पर attribute नहीं, बल्कि property set होती है
    • related docs: Lit expressions

3 टिप्पणियां

 
GN⁺ 2024-04-27
Hacker News की राय
  • data- attributes* का इस्तेमाल लेख में बताए गए तरीकों के बीच एक अच्छा समझौता बन जाता है
    ये attributes JavaScript में dataset की read/write properties के रूप में अपने-आप expose हो जाते हैं, इसलिए document.getElementById('myDiv').dataset.payload == "something" की तरह access किए जा सकते हैं
    बस ध्यान रखना चाहिए कि HTML attributes kebab-case में होते हैं और JavaScript camelCase में, इसलिए data-my-cool-data-attribute dataset.myCoolDataAttribute बन जाता है

    • केस notation का automatic conversion मुझे सचमुच पसंद नहीं है
      camelCase इस्तेमाल करने वाले कई ecosystems में uppercase abbreviations को कैसे handle किया जाए, इसकी कोई स्थापित convention नहीं है, इसलिए dataset.myID जैसे cases ambiguous हो जाते हैं
    • kebab-case और camelCase conversion से बचने के लिए Element.hasAttribute('data-thing'), Element.getAttribute('data-thing'), Element.setAttribute('data-thing', '...') जैसे methods इस्तेमाल करता/करती हूँ
      DOM में inspect या debug करते समय अटपटा conversion नहीं करना पड़ता, इसलिए intent कहीं ज्यादा साफ रहता है
    • MDN का data attributes documentation HTML syntax, JavaScript access, CSS access और accessibility से जुड़ी सावधानियां cover करता है: https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Us...
      साथ ही https://developer.mozilla.org/en-US/docs/Web/HTML/Global_att... में data-* global attributes को “custom data attributes जो scripts को HTML और DOM representation के बीच अपनी जानकारी exchange करने देते हैं” के रूप में समझाया गया है
    • ये attributes कुछ हद तक CSS से भी access किए जा सकते हैं
    • यह JavaScript execution contexts के बीच communication का एक और दिलचस्प तरीका भी है
      यहां context से मतलब जरूरी नहीं कि अलग-अलग iframe हों; बल्कि browser extensions जैसी स्थितियां भी हैं, जहां उसी DOM को access करने वाले अलग JavaScript execution contexts बनाए जाते हैं
      developer tools protocol की terminology में इन्हें isolated worlds भी कहा जाता है
  • लेख में जिन चीजों पर बात की गई है, वे ऐसी complexity और behavior दिखाती हैं जिनसे जीवन में कोई खास फायदा नहीं
    ऐसे behavior में फायदे के बिना सिर्फ नुकसान हैं, और specification को बस DOM objects और JavaScript objects को एक ही चीज define करके attributes और properties को भी एक ही concept बना देना चाहिए था

    • अगर ऐसी limitation “बस” होती, तो ज्यादातर modern UI frameworks बिल्कुल काम नहीं करते
      DOM node में non-string values store कर पाना साफ तौर पर एक फायदा है, और इसे हल्के में टालने वाली बात नहीं है
    • “बस” वाले हिस्से को छोड़ दें तो सहमत हूँ
      जब तक आप यह demand नहीं करते कि सभी properties सिर्फ strings ही हो सकती हैं, यह बिल्कुल simple नहीं है
      numbers के साथ conversion, objects set कर सकने वाली properties, और ऐसे properties जिनका attributes से कोई mapping नहीं है—सब consider करना पड़ेगा
      फिर भी अगर 100% fixed convention या rule होता तो बेहतर होता, लेकिन यह आसान काम नहीं है
    • ऐसा करने पर DOM interface में non-string values नहीं रख पाएंगे, और methods भी शामिल होते हैं, इसलिए DOM functionality का बड़ा हिस्सा गायब हो जाएगा
    • मौजूदा DOM API में attributes और properties को एक-दूसरे के symmetric बनाना मुश्किल है
      addEventListener जैसे methods individual DOM elements की prototype properties हैं, लेकिन string attribute के रूप में देखें तो उनका कोई मतलब नहीं बनता
      तब DOM element methods को HTMLElement.addEventListener(foo, 'some-event', e => console.log(e)); जैसी free functions बनना पड़ेगा; यह taste की बात है, फिर भी JavaScript में object method calls इस्तेमाल कर पाना बेहतर लगता है
    • मुझे समझ नहीं आता कि दोनों अलग क्यों होने चाहिए
      DOM elements के पास setAttribute से state बदलने वाला बहुत specific interface है, और जब उस interface के जरिए DOM को message भेजने के लिए बनाए गए JavaScript object पर सिर्फ property जोड़ दी जाए, तो उसे automatically route होने की उम्मीद क्यों करनी चाहिए—यह सवाल है
      ऐसा API बेहतर experience दे सकता है, लेकिन इसमें कुछ मुश्किलें हैं, और फिर भी शायद यह ज्यादा साफ-सुथरा होगा
      शायद backend code बहुत लंबे समय तक लिखने की वजह से, ऐसे interfaces को देखकर लगता है कि अंदर बहुत अजीब चीजें चल रही हैं, और अतीत के किसी मददगार developer ने जितना संभव हो उतना safe wrapper दे दिया है
  • समझने में मददगार नजरिया यह है कि संकीर्ण अर्थ में attribute एक DOM node, यानी Attr node है
    इस node में name, value, ownerElement, prefix जैसी properties हो सकती हैं, और पूरे रूप में इसे array नहीं बल्कि NamedNodeMap के रूप में owning element की attributes property value से access किया जा सकता है
    इसलिए getAttribute(name) नाम misleading है; वास्तव में यह attribute node खुद नहीं, बल्कि उस attribute node की value property return करता है, इसलिए यह getAttributeValue(name) के ज्यादा करीब है
    संदर्भ: 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

    • वह explanation सही है, लेकिन मुझे नहीं पता कि setAttribute, getAttribute, getAttributeNames, hasAttribute से न हो सकने वाला और attribute node या el.attributes से ही हो सकने वाला कोई practical काम है या नहीं
      attribute nodes को elements के बीच move भी नहीं किया जा सकता, और element के अंदर attribute nodes का order भी नहीं बदला जा सकता
  • Jake, तो इसका क्या करें: https://jakearchibald.com/2023/against-self-closing-tags-in-...

    • “आप मेरे ब्लॉग पर यह syntax देखेंगे, क्योंकि Prettier ऐसा करता है और मुझे Prettier वाकई बहुत पसंद है”
  • properties को अपडेट न करने वाली दलील समझ आती है, लेकिन CSS से target कर पाना उपयोगी है

    • इसलिए मैंने कहा था कि input elements के :checked की तरह एक pseudo-class भी होना चाहिए
    • मेरे लिए भी बाकी सभी वजहों से ज़्यादा यही case बड़ा है
      debugger से गुजरने के बजाय DOM को तुरंत देख पाना debugging के लिए कहीं आसान है
  • शायद सबसे अहम फर्क persistence है, जिसे लेख में नहीं कवर किया गया
    attributes तब तक बनी रहती हैं जब तक उस DOM tree के उसी root object तक access संभव है, जैसे page छोड़े बिना
    object properties सिर्फ तब तक रहती हैं जब तक वह object garbage collection में नहीं चला जाता

    • object उतनी देर मौजूद रहता है जितनी देर attributes वाला DOM node मौजूद रहता है, इसलिए lifecycle समान है
      अगर DOM node clone हो जाए या serialize/deserialize से गुजरे, तो वह वही attributes रखने वाला पूरी तरह अलग DOM node बन जाता है, इसलिए उसमें दूसरे node की non-default properties नहीं होंगी
    • यहां attributes और properties के मौजूदा फर्क के अलावा व्यवहार में कोई वास्तविक फर्क नहीं है
    • यह फर्क असल में कैसे सामने आता है, यह जानने की उत्सुकता है
  • दिलचस्प लेख है
    JavaScript के DOM elements को हमेशा एक तरह के proxy की तरह देखा है
    वे वास्तविक DOM element पर काम करने देते हैं, लेकिन साथ ही वे बस JavaScript objects भी हैं, इसलिए वास्तविक element से interact करने वाले functions इस्तेमाल करने के अलावा values assign करके मनचाहा काम किया जा सकता है—ऐसा लगता था

  • examples के साथ अच्छी तरह समझाया गया है और पढ़ने में अच्छा है; खासकर कई ऐसी details हैं जो अक्सर छूट जाती हैं, इसलिए यह कई लोगों के लिए मददगार हो सकता है

  • DOM properties को IDL attributes भी कहा जाता है

    • सही है, लेकिन मैंने जानबूझकर उस term से बचा
      spec writers के बाहर IDL attributes कहने वाले लोग कम ही हैं, और दोनों को attributes कहना बहुत भ्रमित कर देता है
  • अच्छा लेख है, और यह सोचने पर मजबूर करता है कि बेहतर expression model कैसा दिखेगा
    अगर HTML में string के अलावा भी attributes हो सकें, और उनकी value scoped script tag की local value को reference करे, तो यह दिलचस्प होगा
    attributes को default settings के रूप में देखना थोड़ा अजीब लगा
    उदाहरण के लिए अगर class attribute सिर्फ default value दिखाए, तो classes toggle करते समय DOM inspector या stringified HTML में active class न दिखे, या inactive class दिखे—यह काफी अजीब होगा

    • मैंने default setting नहीं कहा था, सिर्फ setting कहा था
      class attribute इस system में ठीक से काम करता है
      document का owner होने के नाते मैं class attribute set करता हूं, और समय के साथ उस setting को बदल सकता हूं, लेकिन यह सिर्फ मैं करता हूं
      किसी alternative system में browser hover या focus state पर react करके खुद classes add/remove करता, लेकिन शुक्र है ऐसा नहीं होता और pseudo-classes इस्तेमाल होती हैं
 
superwoou 2024-05-03

https://emewjin.github.io/html attribute (Attributes) और DOM property (Properties) के बीच का अंतर

 
superwoou 2024-04-27

लगता है attribute और property दोनों का अनुवाद एक ही "गुण" के रूप में कर दिया गया है..