TIP

  • 웹 브라우저는 ``html <head>``를 먼저 읽고 ``html <body>``를 읽는다.
  • 일반적으로 ``html <script>``는 가독성을 위해 ``html <head>``에 넣는 것이 좋다.
  • 웹 브라우저는 ``html <script>`` 내의 내용을 위에서 부터 한 줄씩 읽기 전에 선언적 함수부터 읽는다.
    선언적 함수 = 함수 선언식. ``js function foo() {}``로 정의된 함수.
    함수 표현식 = 익명 함수. ``js var foo = function () {}`` 형태.
    그래서 함수 선언 부분이 함수 호출 부분보다 밑에 있어도 상관은 없지만, 이는 좋은 습관은 아니다.
    익명 함수의 경우는 위에서 부터 차례로 읽어나가는 때에 읽히므로 먼저 읽히지 않는다.

  • 그러나 다른 ``html <script>``에 있는 함수는, 함수를 호출하는 ``html <script>`` 부분이 함수를 정의하는 ``html <script>`` 부분 보다 밑에 위치해 있어야 호출된다.
  • 웹 브라우저에서 각각의 ``html <script>``는 컴파일되어 실행되는 하나의 컴파일 단위이기 때문이다.

    JS에는 링커가 없기 때문에 모든 문장을 하나의 전역 namespace에 몰아 넣는다.

  • 난독화 decode는 파이어폭스 애드온 JavaScript Deobfuscator (github)이게 제일 나은 것 같다.

 

현재 보고있는 페이지의 IP, PORT

```js
console.log(document.domain)
console.log(location.port)
```
 

async / defer

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

그래서 용량이 큰 외부 script를 불러오게 되면 내려받는 동안 HTML parsing이 이루어지지 않아 페이지 로딩속도가 느려지게 된다.
이를 해결할 수 있는 방법이 `` sync / defer`` 속성이다.
```html
<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`` 순으로 빠르다.
```js
$(function() {});    equivalent to    $(document).ready(function() {});
window.onload = function(){};
```

 

window 객체

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

 

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

브라우저 객체 모델은 웹 브라우저와 관련된 객체의 집합을 의미한다.

대표적으로 window 객체가 있고, 그 하위에 다음과 같은 객체들이 있다.

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

DOM 생성

정적 생성

HTML element를 JS에서 이용할 수 있는 객체로 만들면 그게 문서 객체다. 

HTML element를 JS로 가져와서 다루기 위해서 예전에는 getElement계열을 사용했다.

```js

document.getElementById('id')

document.getElementsByTagName('tag')

document.getElementsByClassName('class')

```

 

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

```js

$("#clstag")

```

 

또는 querySelector를 사용한다.

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

```js

document.querySelector(".myclass");

```

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

 

 

Note )

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

 

불러온 문서 객체를 이용해 내용을 수정할 수 있다. 

innerHTML나 textContent을 이용해 `` body`` element의 `` content``를 수정.

```js 

document.body.textContent = "kkk";

```

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

 

Note )

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

 

동적 생성

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

```js

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에 붙인다.

```

 

결과는 다음 코드를 입력한 것과 동일하다.

``html <a href="testh.html" name="testhname">testh</a>``

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

innerHTML이나 jQuery를 사용하면 간단히 동적 생성할 수 있다. 

``js document.body.innerHTML+= "<h1 id="header1">innerHTML!</h1>";``

 

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

 

DocumentFragments

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

 

 

'JS Stack > Front-end' 카테고리의 다른 글

[jQuery] CDN, Usage  (0) 2017.04.13
쿠키(Cookie)와 저장소(Storage)  (0) 2017.04.12
[Front-end] DOM 이벤트 모델  (0) 2017.03.15
HTML (HTML5)  (0) 2017.03.01
XML  (0) 2016.11.19