Zephyrnet Logosu

Adlandırılmış Öğe Kimliklerine JavaScript Globalleri Olarak Başvurulabilir

Tarih:

Kimlikli DOM öğelerine JavaScript'te global değişkenler olarak erişilebildiğini biliyor muydunuz? Bu, sonsuza kadar ortalıkta olan şeylerden biri ama ben gerçekten ilk defa bu konuyu araştırıyorum.

Eğer bunu ilk kez duyuyorsanız, kendinizi hazırlayın! HTML'deki bir öğeye bir kimlik ekleyerek bunu çalışırken görebiliriz:

Normalde, kullanarak yeni bir değişken tanımlardık. querySelector("#cool") or getElementById("cool") bu öğeyi seçmek için:

var el = querySelector("#cool");

Ama aslında zaten erişimimiz var #cool bu saçmalık olmadan:

Bu yüzden herhangi id - veya name özellik, bu konuda - HTML'de JavaScript kullanılarak erişilebilir window[ELEMENT_ID]. Tekrar ediyorum, bu tam olarak "yeni" değil ama görülmesi gerçekten alışılmadık bir durum.

Tahmin edebileceğiniz gibi, küresel kapsama adlandırılmış referanslarla erişmek pek de iyi bir fikir değil. Bazı insanlar buna "küresel kapsamı kirleten şey" adını vermeye başladı. Bunun nedenine gireceğiz, ama önce…

Bazı bağlam

Bu yaklaşım HTML spesifikasyonunda özetlenen, burada "adlandırılmış erişim" olarak tanımlanır Window nesne."

Bu özelliği uygulayan ilk kişi Internet Explorer oldu. Diğer tüm tarayıcılar da bunu ekledi. Gecko, o zamanlar doğrudan standartlar modunda desteklemeyen tek tarayıcıydı, bunun yerine deneysel bir özellik yapmayı tercih etti. Bunu hayata geçirmek konusunda tereddütler vardı ama tarayıcı uyumluluğu adına ilerledi (Gecko bile denedi WebKit'i ikna edin standartlar modundan çıkarmak için) ve sonunda Firefox 14'te standartlar moduna geçti.

İyi bilinmeyen bir şey, tarayıcıların, oluşturulan genel öğelerin web sayfasını bozmamasını sağlamak için değişen başarı derecelerine sahip birkaç önlem almak zorunda kalmasıdır. Böyle bir önlem…

Değişken gölgeleme

Muhtemelen bu özelliğin en ilginç kısmı, adlandırılmış öğe referanslarının mevcut global değişkenleri gölgele. Yani, eğer bir DOM öğesi bir id zaten global olarak tanımlanmışsa, mevcut olanı geçersiz kılmaz. Örneğin:


  
    window.foo = "bar";
  


  
I won't override window.foo
console.log(window.foo); // Prints "bar"

Ve bunun tersi de doğrudur:

I will be overridden :(
window.foo = "bar"; console.log(window.foo); // Prints "bar"

Bu davranış önemlidir çünkü aşağıdaki gibi tehlikeli geçersiz kılmaları geçersiz kılar:

aksi takdirde geçersiz kılarak bir çakışma yaratacak olan alert API'dir. Bu koruma tekniği, eğer benim gibiyseniz, bunu ilk kez öğrenmenizin nedeni olabilir.

Adlandırılmış küresellere karşı dava

Daha önce global adlandırılmış öğeleri referans olarak kullanmanın iyi bir fikir olmayabileceğini söylemiştim. Bunun pek çok nedeni var ve bunlar TJ VanToll blogunda güzel bir şekilde konuyu ele aldı ve burada özetleyeceğim:

  • DOM değişirse referans da değişir. Bu, bazılarını gerçekten “kırılgan” yapar (spesifikasyonun süresi bunun için) HTML ve JavaScript arasındaki endişelerin ayrılmasının çok fazla olabileceği kod.
  • Yanlışlıkla yapılan referanslar çok kolaydır. Basit bir yazım hatası, adlandırılmış bir globale atıfta bulunarak size beklenmedik sonuçlar verebilir.
  • Tarayıcılarda farklı şekilde uygulanır. Örneğin, bir çapaya erişebilmemiz gerekir. id - Örneğin — ancak bazı tarayıcılar (yani Safari ve Firefox) bir ReferenceError konsolda.
  • Düşündüğünüzü geri vermeyebilir. Spesifikasyona göre, DOM'da aynı adlı öğenin birden fazla örneği olduğunda, örneğin iki örnek

    — tarayıcı bir sonuç döndürmelidir HTMLCollection bir dizi örnekle. Ancak Firefox yalnızca ilk örneği döndürür. Sonra tekrardan, teknik özellik diyor bir örneğini kullanmalıyız id zaten bir elementin ağacında. Ancak bunu yapmak bir sayfanın çalışmasını veya buna benzer bir şeyi durdurmaz.

  • Belki bir performans maliyeti vardır? Demek istediğim, tarayıcının bu referans listesini yapması ve sürdürmesi gerekiyor. Birkaç kişi test yaptı bu StackOverflow iş parçacığında, adı geçen globallerin aslında bulunduğu yer tek testte daha yüksek performans ve daha yeni bir testte daha az performans.

Ek hususlar

Diyelim ki, adlandırılmış globallerin kullanılmasına yönelik eleştirileri bir kenara attık ve yine de kullanıyoruz. Hepsi iyi. Ancak bunu yaparken dikkate almak isteyebileceğiniz bazı şeyler var.

çoklu dolgular

Her ne kadar son durum gibi görünse de, bu tür genel kontroller çoklu doldurmalar için tipik bir kurulum gereksinimidir. Yeniyi kullanarak bir çerez ayarladığımız aşağıdaki örneğe göz atın. CookieStore APIhenüz desteklemeyen tarayıcılarda çoklu doldurma:


  
  
    // Polyfill the CookieStore API if not yet implemented.
    // https://developer.mozilla.org/en-US/docs/Web/API/CookieStore
    if (!window.cookieStore) {
      window.cookieStore = myCookieStorePolyfill;
    }
    cookieStore.set("foo", "bar");
  

Bu kod Chrome'da gayet iyi çalışıyor ancak Safari'de aşağıdaki hatayı veriyor:

TypeError: cookieStore.set is not a function

Safari'nin desteği yok CookieStore Bu yazının yazıldığı an itibariyle API. Sonuç olarak çoklu doldurma uygulanmaz çünkü img öğe kimliği, öğe kimliğiyle çatışan genel bir değişken oluşturur. cookieStore küresel.

JavaScript API güncellemeleri

Durumu tersine çevirebilir ve tarayıcının JavaScript motorunda yapılan güncellemelerin adlandırılmış bir öğenin genel referanslarını bozabileceği başka bir sorun daha bulabiliriz.

Örneğin:


  
  
    window.BarcodeDetector.focus();
  

Bu komut dosyası giriş öğesine bir referans alır ve onu çağırır. focus() üstünde. Düzgün çalışıyor. Yine de nasıl olduğunu bilmiyoruz ve kazandırdı çalışmaya devam edecek.

Gördüğünüz gibi, giriş öğesine referans vermek için kullandığımız global değişken, tarayıcılar girdi öğesini desteklemeye başlar başlamaz çalışmayı durduracaktır. BarcodeDetector API. Bu noktada, window.BarcodeDetector global artık giriş öğesine bir referans olmayacak ve .focus() bir “atacakwindow.BarcodeDetector.focus bir işlev değil” hatası.

Bonus: Adlandırılmış öğelerin tümü küresel referanslar oluşturmaz

Komik bir şey duymak ister misin? Yaralanmayı daha da kötüleştirmek için, adlandırılmış öğelere yalnızca adların harflerden başka bir şey içermemesi durumunda küresel değişkenler olarak erişilebilir. Tarayıcılar, örneğin özel karakterler ve sayılar içeren bir kimliğe sahip bir öğe için genel bir referans oluşturmaz. hello-world ve item1.

Sonuç

Buraya nasıl geldiğimizi özetleyelim:

  • Tüm önemli tarayıcılar otomatik olarak her DOM öğesine genel referanslar oluşturur. id (veya bazı durumlarda bir name özellik).
  • Bu öğelere küresel referansları aracılığıyla erişmek güvenilmez ve potansiyel olarak tehlikelidir. Kullanmak querySelector or getElementById yerine.
  • Global referanslar otomatik olarak oluşturulduğundan kodunuz üzerinde bazı yan etkileri olabilir. Bu, kullanmaktan kaçınmak için iyi bir neden id Gerçekten ihtiyacınız olmadığı sürece bu özellik.

Günün sonunda, JavaScript'te adlandırılmış globalleri kullanmaktan kaçınmak muhtemelen iyi bir fikirdir. Daha önce bunun nasıl "kırılgan" koda yol açtığına dair spesifikasyondan alıntı yapmıştım, ancak asıl konuyu anlatmak için işte tam metin:

Genel bir kural olarak buna güvenmek kırılgan koda yol açacaktır. Örneğin, web platformuna yeni özellikler eklendikçe hangi kimliklerin bu API ile eşleneceği zamanla değişebilir. Bunun yerine şunu kullanın: document.getElementById() or document.querySelector().

Bence HTML spesifikasyonunun kendisinin bu özellikten uzak durmayı tavsiye etmesi kendi adına konuşuyor.

spot_img

En Son İstihbarat

spot_img

Bizimle sohbet

Merhaba! Size nasıl yardım edebilirim?