(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 this
는 window
객체를 의미하게 된다. 그래서 생성자 함수는 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는 처리할수 없음.
- FE js에서 body에 접근하는 인터페이스를 안만들어 두었음.
- https://stackoverflow.com/questions/1409013/how-to-read-the-post-request-parameters-using-javascript