<script> 태그를 document.write ()로 쓸 때 왜 분리합니까?


268

일부 사이트 (또는 클라이언트에 자바 스크립트 코드를 제공하는 광고주)가 통화 내에서 태그 <script>및 / 또는 </script>태그 를 분할하는 기술을 사용하는 이유는 무엇 document.write()입니까?

예를 들어 아마존도이 작업을 수행합니다.

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

답변:


373

</script>그렇지 않으면 <script></script>엔 클로징 블록이 너무 일찍 종료되므로 분리해야 합니다. 정말로이 나뉘어 있어야 <하고 /스크립트 블록이되도록 (SGML)에 따라 예상되기 때문에, 임의의 종료 태그 열기 (ETAGO) 시퀀스 (즉, 종료 </) :

STYLE 및 SCRIPT 요소는 데이터 모델에 CDATA를 사용하지만 이러한 요소의 경우 사용자 에이전트가 CDATA를 다르게 처리해야합니다. 마크 업 및 엔터티는 원본 텍스트로 처리하고 그대로 응용 프로그램에 전달해야합니다. 문자 시퀀스 " </"(end-tag open delimiter) 의 첫 번째 항목은 요소 내용의 끝을 종료하는 것으로 간주됩니다. 유효한 문서에서 이는 요소의 종료 태그입니다.

그러나 실제로 브라우저는 실제 </script>닫기 태그 에서 CDATA 스크립트 블록 구문 분석 만 종료 합니다.

XHTML에는 스크립트 블록에 대한 특별한 처리가 없으므로 그 안에 있는 <(또는 &) 문자는 &escaped;다른 요소와 같아야합니다 . 그러나 XHTML을 구식 HTML로 구문 분석하는 브라우저는 혼란 스러울 것입니다. CDATA 블록과 관련된 해결 방법이 있지만 이스케이프 처리되지 않은 문자를 사용하지 않는 것이 가장 쉽습니다. 두 가지 유형의 파서 모두에서 작동하는 스크립트에서 스크립트 요소를 작성하는 더 좋은 방법은 다음과 같습니다.

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

30
\/의 유효한 이스케이프 시퀀스입니다 /. 왜 문자열 리터럴 이스케이프 대신 이것을 사용하지 <않습니까? 예 document.write('<script src=foo.js><\/script>');. 또한 요소를 </script>닫을 수있는 유일한 문자 순서는 아닙니다 <script>. 여기에 몇 가지 추가 정보를 원하시면 : mathiasbynens.be/notes/etago
마티아스 Bynens

11
@Mathias : <\/script>이 경우에는 문제가 없지만 HTML에서만 작동합니다. 추가 CDATA 섹션 줄 바꿈이없는 XHTML에서는 여전히 형식 오류입니다. 또한 HTML 및 XHTML 모두에서 유효하지 않은 \x3C인라인 이벤트 핸들러 속성에서 사용할 수 <있으므로 더 넓은 적용 가능성을 갖습니다. 모든 컨텍스트에서 JS 문자열 리터럴에서 민감한 문자를 이스케이프 처리하는 쉬운 방법 중 하나를 선택하는 경우 내가 갈 것입니다.
bobince 2016 년

3
HTML에서는 <인라인 이벤트 핸들러 속성에서 사용할 수 있습니다. html5.validator.nu/… 그리고 당신은 \x3Csich 의 XHTML 호환성에 대해 옳습니다 . 그러나 XHTML은 어쨌든 지원하지 않습니다 document.write(또는 innerHTML).
Mathias Bynens 2016 년

2
@ MathiasBynens— document.write는 관련이 없습니다. 단지 예일 뿐입니다. OP는 innerHTML을 사용했을 수 있습니다 </. 마크 업 파서에서 문자 시퀀스를 숨기는 것이 어디에서나 숨겨지는 것에 관한 것입니다. 대부분의 파서는 스크립트 요소 내에서 엄격하게 사용하지 않아야 할 때 스크립트 요소 내에서 허용합니다 (그러나 HTML 파서는 매우 관대합니다). 당신은하지만 올바른 <\/HTML에 대한 모든 경우에 충분하다.
RobG

3
시작 <이스케이프를 이스케이프해야한다고 생각하지 않습니다 .... document.write('<script src="foo.js">\x3C/script>')모든 브라우저에서 IE6으로 돌아 오는 것으로 충분합니다. (HTML5에 필요하지 않기 때문에 type 속성을 제외하고 브라우저에서 필요로하지도 않습니다.)
Matt Browne

34

다음은 이스케이프 형식없이 스크립트 태그를 인라인으로 생성 (즉시 실행) 할 때 사용한 또 다른 변형입니다.

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

(참고 : 대부분의 인터넷 예제와는 달리 type="text/javascript", 둘러싼 태그 나 생성 된 태그를 설정하지 않았습니다 : 기본적으로 브라우저가 없으므로 중복되지 않지만 아프지 않습니다. 동의하지 않으면).


좋은 지적 : 유형. 기본값은 HTML5에서 "text / javascript"로 정의되므로 쓸모없는 속성입니다. w3.org/html/wg/drafts/html/master/…
누가

8
이 변형은 실제로 축소 될 수 있기 때문에 허용되는 답변보다 낫습니다. 이 'x3C / script>'는 축소 후 '</ script>'가됩니다.
Zoltan Kochan

20

브라우저의 HTML 파서가 <script>와 주로 </ script>를 실제 스크립트의 닫는 태그로 해석하지 못하도록하기위한 것이라고 생각하지만 document.write를 사용하는 것이 스크립트를 평가하는 훌륭한 아이디어라고 생각하지 않습니다 블록, 왜 DOM을 사용하지 않습니까?

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

4
... 조기 스크립트 블록을 닫는 파서를 방지 할 필요가있다
roenving

9

Bobince가 게시 한 솔루션은 완벽하게 작동합니다. 나는 미래의 방문객들에게도 대안을 제시하고 싶었다

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

이 예제에서는 유스 케이스를 보여주기 위해 jQuery에 대한 조건부로드를 포함시켰다. 누군가에게 도움이 되길 바랍니다!


3
프로토콜을 감지 할 필요가 없음-프로토콜이없는 URI가 제대로 작동 함 ( '//foo.com/bar.js'등)
dmp

3
비동기를 설정할 필요가 없습니다. 동적으로 생성 된 모든 스크립트 태그에 설정됩니다.
Noishe

저를 구했습니다! document.write (<script>)를 사용할 때 내 사이트에 빈 화면이 표시되었습니다. 이것은 효과가 있었다.
Tomas Gonzalez

프로토콜이 file : // 인 파일 시스템에서 실행할 때를 제외하고 @dmp
mplungjan

9

</script>자바 스크립트 문자열 litteral 내부가 예기치 않은 동작을 일으키는 닫는 태그로 HTML 파서에 의해 해석됩니다 ( JSFiddle에 예 참조 ).

이것을 피하기 위해 주석 사이에 자바 스크립트를 배치 할 수 있습니다 (이 스타일의 코딩은 브라우저에서 Javascript가 제대로 지원되지 않았던 일반적인 관행이었습니다). 이것은 작동합니다 ( 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>

...하지만 솔직히 말해서 사용하는 document.write것이 모범 사례라고 생각 하는 것이 아닙니다. 왜 DOM을 직접 조작하지 않습니까?

<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
순수한 JS를 사용하려면 여전히 document.write를 사용하고 싶을 것입니다.)
Nirav Zaveri

죄송합니다. 작성해야합니다. 여기에는 jQuery 라이브러리가 필요합니다. document.body.append를 사용했을 때 document.body.append가 함수가 아니라는 오류가 발생했습니다.
Nirav Zaveri

1
죄송합니다, 내 실수 : append대신 썼습니다 appendChild. 답변을 수정했습니다. 알아 주셔서 감사합니다!
Mathieu Rodic

1
이것은 문자열을 수동으로 나누는 것보다 훨씬 일반적으로 보입니다. 예를 들어 문자열이 템플릿 엔진에 의해 삽입 된 경우 분할이 불가능합니다.
w1th0utnam3
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.