2008-10-25 16 views
242

¿Por qué algunos sitios (o anunciantes que dan a los clientes código JavaScript) emplean una técnica de división de las etiquetas <script> y/o </script> entre document.write() llamadas?¿Por qué dividir la etiqueta <script> al escribirla con document.write()?

me di cuenta de que Amazon hace esto así, por ejemplo:

<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> 

Respuesta

340

</script> tiene que dividirse porque de lo contrario terminaría demasiado pronto el bloque <script></script> que lo contiene. Realmente se debe dividir entre la < y la /, porque un bloque de script se supone (según SGML) para ser terminated by any end-tag open (ETAGO) sequence (i.e. </):

Aunque el estilo y los elementos de script usan CDATA por su modelo de datos, para estos elementos, CDATA debe ser manejado de manera diferente por los agentes de usuario. El marcado y las entidades se deben tratar como texto sin formato y pasar a la aplicación como está. La primera aparición de la secuencia de caracteres "</" (delimitador abierto de etiqueta final) se considera como la terminación del final del contenido del elemento. En documentos válidos, esta sería la etiqueta final para el elemento.

Sin embargo, en la práctica los navegadores único fin analizar un bloque de script CDATA en un primer etiqueta real </script>.

En XHTML no existe un manejo especial para bloques de script, por lo que cualquier carácter < (o) debe ser &escaped; como en cualquier otro elemento. Sin embargo, los navegadores que están analizando XHTML como HTML de la vieja escuela se confundirán. Existen soluciones provisionales que involucran bloques CDATA, pero es más fácil simplemente evitar el uso de estos caracteres sin protección. Una mejor manera de escribir un elemento de script desde el guión que funciona en cualquier tipo de programa de análisis sería:

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

'\ /' es una secuencia de escape válida para '/ ', ¿por qué no usar sólo que en vez de esos escapes literales de cadena para '<'? P.ej. 'document.write ('' no es la única secuencia de caracteres que puede cerrar un elemento '

20

Creo que es para prevenir el analizador HTML del navegador de interpretar el guión < >, y sobre todo la </script > como la etiqueta de cierre de la escritura real, sin embargo, no creo que el uso de document.write es una excelente idea para evaluar los bloques de script, ¿por qué no usar el DOM ...

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

Es necesario evitar que el analizador se cierre el script del bloque antes de tiempo ... – roenving

18

Aquí es otra variación que he usado cuando se quiere generar una línea etiqueta de script (por lo que se ejecuta inmediatamente) sin necesidad cualquier forma de escapes:

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

(Nota: al contrario de la mayoría de los ejemplos en la red, no estoy estableciendo en type="text/javascript" ni la etiqueta donde se incluye, ni el generado una: no hay navegador que no tengan dicho como predeterminado , por lo que es redundante, pero tampoco le hará daño, si no está de acuerdo).

+0

Buen punto re: escribir. El valor predeterminado se define como "texto/javascript" a partir de HTML5, por lo que es un atributo inútil. http://www.w3.org/html/wg/drafts/html/master/scripting-1.html#attr-script-type – Luke

+6

Este es mejor que la respuesta aceptada porque esta variación puede ser realmente minimizada. Este 'x3C/script>' se convertirá en '' después de la minificación. –

6

La solución que Bobince publicó funciona perfectamente para mí. Quería ofrecer un método alternativo, así como para los futuros visitantes:

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); 
    })(); 
} 

En este ejemplo, he incluido una carga condicional para jQuery para demostrar caso de uso. Espero que sea útil para alguien!

+3

no es necesario detectar el protocolo: el URI sin protocolo funciona bien ('//foo.com/bar.js', etc.) – dmp

+2

sin necesidad de establecer la sincronización. está configurado para todas las etiquetas de scripts creadas dinámicamente. – Noishe

+0

¡Me salvó! Al usar document.write (

6

</script> dentro de Javascript string litteral es interpretado por el analizador de HTML como una etiqueta de cierre, lo que causa un comportamiento inesperado (see example on JSFiddle).

Para evitar esto, puede colocar su javascript entre comentarios (este estilo de codificación era una práctica común, cuando JavaScript no era compatible con los navegadores). Esto funciona (see example in JSFiddle):

<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> 

... pero para ser honesta, utilizando document.write no es algo que consideraría la mejor práctica. ¿Por qué no manipular el DOM directamente?

<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> 
+0

Si quiere usar JS puro, querrá seguir usando document.write;) –

+0

@NiravZaveri ¿Por qué? ¿Cómo es este código JS no puro? –

+0

Disculpa, quise escribir: esto requiere la Biblioteca jQuery, ¿verdad? Cuando lo usé, document.body.append, arrojó un error que document.body.append no es una función. –

Cuestiones relacionadas