Post

(JS) 팁, 문서 객체 모델(DOM)

TIP

  • 웹 브라우저는 <head>를 먼저 읽고 <body>를 읽는다.
  • 일반적으로 <script>는 가독성을 위해 <head>에 넣는 것이 좋다.
  • 웹 브라우저는 <script> 내의 내용을 위에서 부터 한 줄씩 읽기 전에 선언적 함수부터 읽는다.
    • 선언적 함수 = 함수 선언식. function foo() {}로 정의된 함수.
    • 함수 표현식 = 익명 함수. var foo = function () {} 형태.
    • 그래서 함수 선언 부분이 함수 호출 부분보다 밑에 있어도 상관은 없지만, 이는 좋은 습관은 아니다.
    • 익명 함수의 경우는 위에서 부터 차례로 읽어나가는 때에 읽히므로 먼저 읽히지 않는다.
  • 그러나 다른 <script>에 있는 함수는, 함수를 호출하는<script> 부분이 함수를 정의하는 <script> 부분 보다 밑에 위치해 있어야 호출된다.
  • 웹 브라우저에서 각각의 <script>는 컴파일되어 실행되는 하나의 컴파일 단위이기 때문이다. JS에는 링커가 없기 때문에 모든 문장을 하나의 전역 namespace 에 몰아 넣는다.
  • 난독화 decode는 파이어폭스 애드온JavaScript Deobfuscator (github )이게 제일 나은 것 같다.
현재 보고있는 페이지의 IP, PORT
1
2
console.log(document.domain)
console.log(location.port)
async / defer

웹 브라우저가 <script>를 만나면 스크립트를 (내려받아) 실행할 때 까지 HTML parsing을 잠시 중단한다.

그래서 용량이 큰 외부 script를 불러오게 되면 내려받는 동안 HTML parsing이 이루어지지 않아 페이지 로딩속도가 느려지게 된다. 이를 해결할 수 있는 방법이 sync / defer 속성이다.

1
2
<script async src="bscript.js" onload="bInit()"></script>
<script defer src="bscript.js" onload="bInit()"></script>

둘 다 스크립트를 내려받는 동안은 HTML parsing을 진행하는데 async는 스크립트를 내려받은 직후 스크립트를 실행하고 defer는 스크립트를 내려받고 계속 HTML parsing을 진행하다 HTML parsing이 끝나는 시점에 스크립트를 실행하게 된다. defer, jQuery, window.onload 순으로 빠르다.

1
2
$(function() {});    equivalent to    $(document).ready(function() {});
window.onload = function(){};
window 객체

브라우저를 통해 JS를 사용할 때 작성하는 코드는 window 객체 내에서 작성되는 것이라고 생각하면 된다. 즉, 브라우저에 있는 JS의 변수와 함수는 window객체의 속성과 메서드가 된다. js alert()등도 사실은 window의 메서드다. new키워드를 사용하지 않은 상태에서 생성자 함수를 호출하게 되는 경우, 그냥 함수를 호출하는 것과 똑같으므로 함수에서 js this키워드를 사용하고 있다면 이 js thiswindow객체를 의미하게 된다. 그래서 생성자 함수는 js new와 함께 사용해야 한다. 페이지의 전체 source를 얻어내려면 window.document를 사용한다. 또는 :root를 사용해도 된다. 즉, window.document가 최상위 DOM (html)이라고 보면 된다.

브라우저 객체 모델(BOM), 문서 객체 모델(DOM)

브라우저 객체 모델은 웹 브라우저와 관련된 객체의 집합을 의미한다. 대표적으로 window 객체가 있고, 그 하위에 다음과 같은 객체들이 있다.

  • location 객체
  • navigator 객체
  • history 객체
  • screen 객체
  • document 객체

이 중 document 객체와 관련된 객체 집합을 DOM, 문서 객체 모델이라 부른다.

DOM 생성

정적 생성

HTML element를 JS에서 이용할 수 있는 객체로 만들면 그게 문서 객체다. HTML element를 JS로 가져와서 다루기 위해서 예전에는 getElement계열을 사용했다.

1
2
3
document.getElementById('id')
document.getElementsByTagName('tag')
document.getElementsByClassName('class')

근데 요즘은 jQuery를 많이 사용한다.

1
$("#clstag")

또는 querySelector를 사용한다. 보통 이걸 사용하는걸 추천하는게 jQuery를 사용하지 않아도 되면서 jQuery가 선택하듯 css selector를 이용해 엘리먼트를 가져올 수 있기 때문에 일관성도 있다. IE8부터 지원하니 호환성 문제도 적고.

1
document.querySelector(".myclass");

http://blog.jeonghwan.net/2018/01/25/before-jquery.html

Note )

  • 아직 HTML parsing이 끝나지 않아서 DOM이 로드되지 않은 시점에 실행되는 경우 null을 반환하므로, onload 등을 사용해서 querySelector() 등의 호출 시점을 문서 객체 로드 이후로 맞춰줘야 한다.

불러온 문서 객체를 이용해 내용을 수정할 수 있다. innerHTML나 textContent을 이용해 body element의 content를 수정.

1
document.body.textContent = "kkk";

이런 식으로 HTML element를 JS로 불러와 속성을 추가하고 값을 변경하는 작업 등을 할 수 있다.

Note )
문서 객체를 가져오면서 HTML element와 기존의 문서 객체 변수와의 연결이 끊어지게 된다. 그래서 JS에서 이미 문서 객체를 가리키는 변수가 있는 상태에서 getElementById()로 다시 문서 객체를 가져오게 되면 기존 변수는 의미 없는 변수가 된다.

동적 생성

반대로 JS로 만든 문서 객체를 HTML element로 생성할 수도 있다. 이를 동적 생성이라 부른다.

1
2
3
4
5
6
7
8
var elem = document.createElement("a");    //element 생성
var textnode = document.createTextNode("testh"); //textnode 생성
elem.href="testh.html";
elem.setAttribute("name", "testhname"); //속성 name="testhname" 추가


elem.appendChild(textnode);  //textnode를 element의 content로 붙인다.
document.body.appendChild(elem); //element를 body에 붙인다.

결과는 다음 코드를 입력한 것과 동일하다. <a href="testh.html" name="testhname">testh</a>

  • Element와 textnode를 각각 만들고, textnode를 Element에 붙인 후 Element를 원하는 곳에 붙인다.
  • 속성은 element.attribute 또는 setAttribute(), getAttribute()로 지정하거나 가져올 수 있다.
  • appendChild()메서드는 객체에 노드를 연결(추가)하는 기능을 한다.
  • 객체에서 노드를 제거할 때는 removeChild()를 사용한다.

innerHTML이나 jQuery를 사용하면 간단히 동적 생성할 수 있다. document.body.innerHTML+= "<h1 id="header1">innerHTML!</h1>";

그러나 브라우저의 reflow 때문에, 복잡한 element들을 다뤄야 하는 경우 아래 방식을 사용하는 것이 좋다.

DocumentFragments

1
var docFragment = document.createDocumentFragment();

문서 객체가 DOM Tree에 추가, 삭제, 변경 될 때 마다 브라우저에서 엘리먼트의 위치와 좌표를 다시 계산하는 reflow가 발생하는데, 이를 최소화 하는 것이 퍼포먼스에 좋다. DocumentFragment는 DOM 구조처럼 element를 추가, 삭제할 수 있지만 메모리에만 존재하고 실제로는 DOM 구조에 속하지 않기 때문에 DocumentFragment를 조작하는 것이 reflow를 유발하지 않는다. 따라서 element를 DocumentFragment에 추가하는 등 이것 저것 조작한 다음, 맨 마지막에 DocumentFragment를 Main DOM Tree에 추가하는 방식으로 사용하게 된다.

FE에서 POST body는 처리할수 없음.

This post is licensed under CC BY 4.0 by the author.