<script> etiketini document.write () ile yazarken neden bölmeliyim?


268

Neden bazı siteler (veya istemcilere javascript kodu veren reklamverenler) <script>ve / veya </script>etiketleri document.write()aramalar arasında bölme tekniği kullanıyor ?

Amazon'un da bunu yaptığını fark ettim, örneğin:

<script type='text/javascript'>
  if (typeof window['jQuery'] == 'undefined') document.write('<scr'+'ipt type="text/javascript" src="http://z-ecx.images-amazon.com/images/G/01/javascripts/lib/jquery/jquery-1.2.6.pack._V265113567_.js"></sc'+'ript>');
</script>

Yanıtlar:


373

</script>aksi halde kapalı <script></script>bloğu çok erken bitireceği için parçalanmalıdır . Gerçekten <ve ile arasında bölünmelidir /, çünkü bir komut dosyası bloğunun (SGML'ye göre) herhangi bir son etiket açık (ETAGO) dizisi (yani </) tarafından sonlandırılması beklenir :

STYLE ve SCRIPT öğeleri veri modelleri için CDATA kullanıyor olsalar da, bu öğeler için CDATA'nın kullanıcı aracıları tarafından farklı şekilde ele alınması gerekir. İşaretleme ve varlıklara ham metin muamelesi yapılmalı ve uygulamaya olduğu gibi aktarılmalıdır. " </" Karakter dizisinin (bitiş etiketi açık sınırlayıcı) ilk oluşumu , öğenin içeriğinin sonunu sonlandırıyor olarak değerlendirilir. Geçerli belgelerde, bu öğenin bitiş etiketi olacaktır.

Ancak uygulamada tarayıcılar yalnızca gerçek bir </script>kapalı etikette bir CDATA komut dosyası bloğunu ayrıştırmaya son verir .

XHTML'de komut dosyası blokları için böyle özel bir işlem yoktur, bu nedenle içindeki herhangi bir <(veya &) karakter &escaped;diğer herhangi bir öğede olduğu gibi olmalıdır . Ancak, eski HTML HTML olarak XHTML'yi ayrıştıran tarayıcılar karışacaktır. CDATA bloklarını içeren geçici çözümler vardır, ancak bu karakterlerin kaçınılmasını önlemek en kolay yoldur. Her iki ayrıştırıcı türü üzerinde çalışan komut dosyasından bir komut dosyası öğesi yazmanın daha iyi bir yolu:

<script type="text/javascript">
    document.write('\x3Cscript type="text/javascript" src="foo.js">\x3C/script>');
</script>

30
\/geçerli bir kaçış dizisidir /, o zaman neden sadece bu dizgi değişmezleri yerine bunun için kullanılmıyor <? Örn document.write('<script src=foo.js><\/script>');. Ayrıca, </script>bir <script>öğeyi kapatabilecek tek karakter dizisi değildir . Burada daha fazla bilgi var: mathiasbynens.be/notes/etago
Mathias Bynens

11
@Mathias: <\/script>bu durumda iyidir, ancak yalnızca HTML'de çalışır; Ekstra CDATA bölüm sarması olmayan XHTML'de, hala iyi biçimlilik hatasıdır. Ayrıca HTML ve XHTML'de de geçersiz olacak \x3Csatır içi olay işleyici özelliklerini kullanabilirsiniz <, bu nedenle daha geniş bir uygulanabilirliğe sahiptir: JS bağlam değişmezlerinde tüm bağlamlar için hassas karakterlerden kaçmanın kolay ve otomatik bir yolunu seçseydim, bu benim için giderdim.
bobince

3
HTML'de <satır içi olay işleyici özniteliklerinde kullanılabilir. html5.validator.nu/… Ve bir sich'in XHTML uyumluluğu konusunda haklısınız \x3C, ancak XHTML zaten desteklemediğinden document.write(veya innerHTML) zaten bunun ne kadar alakalı olduğunu görmüyorum.
Mathias Bynens

2
@ MathiasBynens - document.writeilgisiz, sadece örnek oluyor. OP innerHTML kullanmış olabilir </, nerede olursa olsun karakter dizisini biçimlendirme ayrıştırıcısından gizlemekle ilgilidir . Çoğu ayrıştırıcı, kesinlikle yapmamaları gerektiğinde bir komut dosyası içinde tolere eder (ancak HTML ayrıştırıcıları çok toleranslıdır). Doğru, ancak <\/her durumda HTML için yeterli.
RobG

3
Ben açılış <kaçmak gerekli olduğunu sanmıyorum .... document.write('<script src="foo.js">\x3C/script>')IE6 için tüm tarayıcılarda yeterli gibi görünüyor. (HTML5'te gerekli olmadığı veya herhangi bir tarayıcı için gerektiği gibi zorunlu olmadığı için type özelliğini bıraktım.)
Matt Browne

34

İşte herhangi bir kaçış biçimine ihtiyaç duymadan satır içi komut dosyası etiketi oluşturmak için kullandığım başka bir varyasyon (bu yüzden hemen yürütülür):

<script>
    var script = document.createElement('script');
    script.src = '/path/to/script.js';
    document.write(script.outerHTML);
</script>

(Not: internetteki örneklerin aksine type="text/javascript", ne kapalı etiketi ne de oluşturulan etiketi ayarlamıyorum: varsayılan olarak buna sahip olmayan bir tarayıcı yok ve bu yüzden gereksiz, ama ya da zarar vermeyecek, katılmıyorsanız).


İyi bir nokta yeniden: yazın. Varsayılan değer HTML5'ten itibaren "metin / javascript" olarak tanımlanır, bu nedenle işe yaramaz bir özelliktir. w3.org/html/wg/drafts/html/master/…
Luke

8
Bu, kabul edilen cevaptan daha iyidir, çünkü bu varyasyon gerçekten küçültülebilir. Bu 'x3C / script>' simge durumuna getirildikten sonra '</script>' olur.
Zoltan Kochan

20

Tarayıcının HTML ayrıştırıcısının <script> ve esas olarak </script> 'i gerçek komut dosyasının kapanış etiketi olarak yorumlamasını önlemek içindir, ancak document.write komutunun komut dosyasını değerlendirmek için mükemmel bir fikir olduğunu düşünmüyorum neden DOM kullanmıyorsunuz ...

var newScript = document.createElement("script");
...

4
Ayrıştırıcının komut dosyası bloğunu erken kapatmasını önlemek gerekir ...
08:53

9

Bobince'nin gönderdiği çözüm benim için mükemmel çalışıyor. Gelecek ziyaretçiler için de alternatif bir yöntem sunmak istedim:

if (typeof(jQuery) == 'undefined') {
    (function() {
        var sct = document.createElement('script');
        sct.src = ('https:' == document.location.protocol ? 'https' : 'http') +
          '://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js';
        sct.type = 'text/javascript';
        sct.async = 'true';
        var domel = document.getElementsByTagName('script')[0];
        domel.parentNode.insertBefore(sct, domel);
    })();
}

Bu örnekte, kullanım durumunu göstermek için jQuery için koşullu bir yük ekledim. Umarım bu birisi için faydalıdır!


3
Protokol tespit etmeye gerek yok - protokolsüz URI gayet iyi çalışıyor ('//foo.com/bar.js' vb.)
dmp

3
zaman uyumsuzluk ayarlamanıza da gerek yoktur. dinamik olarak oluşturulan tüm komut dosyası etiketleri için açıktır.
Noishe

Beni kurtardı! Document.write (<script>) kullanırken sitem boş bir ekran gösteriyordu. Bu işe yaradı.
Tomas Gonzalez

@dmp Protokolün dosya olacağı dosya sisteminden çalıştırılma durumu hariç: //
mplungjan

9

</script>JavaScript dize edebî içindeki beklenmeyen davranışlar (neden bir kapanış etiketi olarak HTML ayrıştırıcı tarafından yorumlanır JSFiddle örneğe bakın ).

Bundan kaçınmak için, javascript'inizi yorumlar arasına yerleştirebilirsiniz (bu kodlama stili yaygın bir uygulamadır, Javascript tarayıcılar arasında zayıf bir şekilde desteklendiğinde). Bu işe yarar ( JSFiddle'daki örneğe bakın ):

<script type="text/javascript">
    <!--
    if (jQuery === undefined) {
        document.write('<script type="text/javascript" src="http://z-ecx.images-amazon.com/images/G/01/javascripts/lib/jquery/jquery-1.2.6.pack._V265113567_.js"></script>');
    }
    // -->
</script>

... ama dürüst olmak gerekirse, kullanmak document.writeen iyi uygulamayı düşündüğüm bir şey değil. Neden DOM'u doğrudan manipüle etmiyorsunuz?

<script type="text/javascript">
    <!--
    if (jQuery === undefined) {
        var script = document.createElement('script');
        script.setAttribute('type', 'text/javascript');
        script.setAttribute('src', 'http://z-ecx.images-amazon.com/images/G/01/javascripts/lib/jquery/jquery-1.2.6.pack._V265113567_.js');
        document.body.appendChild(script);
    }
    // -->
</script>

1
Saf JS kullanmak istiyorsanız, yine de document.write kullanmak istersiniz;)
Nirav Zaveri

Üzgünüm, yazmak istedim - bu jQuery Kütüphanesi gerektirir, değil mi? Ne zaman kullandığım, document.body.append, document.body.append bir işlev değildir bir hata attı.
Nirav Zaveri

1
Maalesef benim hatam: Yazdığım appendyerine appendChild. Yanıt düzeltildi. Fark ettiğin için teşekkürler!
Mathieu Rodic

1
Bu, dizeyi manuel olarak bölmekten çok daha genel görünüyor. Örneğin, dize bir şablon motoru tarafından eklenirse bölme mümkün değildir.
w1th0utnam3
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.