저번 포스팅에서 DOM에 대해 알아보았고 간단한 JavaScript 코드를 통해 브라우저를 조작하는 것을 해보았다. 이번 포스팅에서는 script 외부연결과 window.onload , window.addEventListener("DOMContentLoaded", listener)에 대해 알아보도록 하자.
< 목차 >
- script 외부연결
- window.onload , window.addEventListener("DOMContentLoaded", listener)
< script 외부연결 >
HTML 문서를 작성할 때 <link>엘리먼트를 사용해 CSS 파일을 외부로부터 가져와서 사용하는 것과 마찬가지로 JavaScript 역시 외부에서 가져와서 사용이 가능하다. script 외부 연결이란 다시말해, HTML 문서의 <head>엘리먼트 안에 <script type="text/javascript">엘리먼트를 작성한 후 다시 해당 엘리먼트 안에 JavaScript를 작성하는 것이 아닌, js 확장자를 가진 외부파일을 따로 생성하여 외부 파일을 HTML 문서와 연결시켜주는 방법인 셈이다.
js 확장자를 가진 파일을 따로 생성한 후 <script>엘리먼트 안에 src 속성을 추가하여 속성값으로 파일경로를 입력해 주기만 하면 외부 파일에서 JavaScript를 좀 더 편하게 작성할 수 있게 된다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="파일경로"></script>
<!-- src 속성의 속성값으로 파일경로를 입력해주면 된다. -->
</head>
<body>
</body>
</html>
< window.onload > ,
< window.addEventListener("DOMContentLoaded", listener) >
window.onload와 window.addEventListener("DOMContentLoaded", listener)에 대해 알아보기 전에 이전 포스팅에서 <script>엘리먼트 안에 작성되었던 JavaScript 코드가 HTML 문서의 <head>엘리먼트 안에 존재했을 때 어떠한 결과가 발생하는지 먼저 확인해보자.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript">
let btn = document.querySelector("#btn")
btn.addEventListener('click', () => console.log('hello world!'))
</script>
</head>
<body>
<button id="btn">버튼</button>
</body>
</html>
실행된 결과를 보면 Cannot read properties of null 이라는 TypeError가 발생한다는 사실을 알 수 있다. 이러한 에러는 <head>엘리먼트 안에서 <script>를 작성하게 되는 경우 브라우저가 <script>를 먼저 해석하기 때문에 발생한다. 브라우저는 html에 작성된 코드들을 순서대로 읽어가면서 처리하게 되는데 <body>엘리먼트 안에 작성된 <button>엘리먼트를 읽기 전에 <script>엘리먼트를 먼저 읽어버려서 btn = document.querySelector("#btn")이 null값이 되는 것이다. null값은 비어있음을 표현하는 값으로 <button>엘리먼트가 아직 랜더가 되기 전 상태에서 <script>가 실행되기 때문에 cannot read properties of null 이라는 에러가 발생하게 되는 것이다.
그렇다면 이러한 에러가 발생하는 것을 막기 위해서는 반드시 JavaScript를 이용해 조작하고 싶은 엘리먼트 다음에 <script>엘리먼트를 작성하여만 하는 것일까? 물론 그렇지 않다. 이러한 부분들을 해결해 주는 것이 바로 window.onload 와 window.addEventListener("DOMContentLoaded", listener)이다. 아래의 코드들을 살펴보면서 좀 더 자세히 알아보자.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="index.js"></script>
</head>
<body>
<button id="btn">버튼</button>
</body>
</html>
// 첫번째
const btnElement = document.querySelector('#btn')
console.log(btnElement)
// 두번째
window.onload = function(){
// code block
const btnElement = document.querySelector('#btn')
console.log('index.js : ' ,btnElement)
}
// 세번째
window.addEventListener('DOMContentLoaded', () => {
// code block
const btnElement = document.querySelector('#btn')
console.log('index.js DOM Content Loaded : ' ,btnElement)
})
위의 html 문서를 살펴보면 <head>엘리먼트 안에 <script>엘리먼트가 작성되어 있고 외부 js 파일과 연결되어 있는 것을 확인할 수 있다. 이러한 상태에서 js 파일에 명시되어 있는 첫번째 코드들이 실행된다면 어떻게 될까? 정답은 null값이 출력되게 된다. <body> 파트가 랜더 되기 전에 해당 코드들이 먼저 실행되기 때문에 document.querySelector("#btn")가 null값을 반환하게 된다.
하지만, 두번째 코드에서처럼 window.onload = function( ) { }을 사용하게 되면 아무 문제 없이 console.log( )가 제대로 작동하는 것을 확인할 수 있다. 여기서 살펴볼 것이 바로 window 객체 안에 있는 onload( ) 메소드이다. onload 메소드는 브라우저에서 html, css, javascript 등 모든 것의 랜더가 끝난 다음에 (모두 로드가 된 상태에서) 실행되는 코드를 만들고 싶을 때 사용하는 메소드이다. 그 결과 <head>엘리먼트 안에 작성하였어도 onload를 주면 에러 없이 실행이 가능해진다. 사용하는 방법은 위에 적혀있는 것처럼 window.onload = function( ) { }과 같이 메소드를 오버라이딩(재정의) 해주는 방식으로 사용한다.
window.onload 방법 이외에도 세번째 코드와 같이 window.addEventListener("DOMContentLoaded", listener)를 작성하여 문제를 해결할 수도 있다. 또한 세번째 방법을 통해 우리는 window 객체에도 addEventListener( ) 메소드가 존재한다는 사실을 확인할 수 있다. 이는 엘리먼트가 아닌 브라우저 자체에도 이벤트를 넣고 싶은 경우가 존재하기 때문이라고 알아두고 넘어가도록 하자.
window.addEventListener('DOMContentLoaded', () => {
// code block
const btnElement = document.querySelector('#btn')
console.log('index.js DOM Content Loaded : ' ,btnElement)
})
window.addEventListener( ) 메소드는 2개의 인자값을 받고 있는데 하나는 "DOMContentLoaded"라는 이벤트를 받았으며 다른 하나인 이벤트 리스너(listener)는 Arrow 함수를 콜백하여 받고 있다. 이벤트 리스너로 콜백 함수를 지정하여 받았기 때문에 "DOMContentLoaded"라는 이벤트가 발생하였을 때 Arrow 함수가 실행되게 되는 것이다.
이제 위의 코드들을 실행한 결과를 살펴보자.
조금 이상한 것을 눈치챈 사람도 있을 것이다. js 파일에서는 분명 window.onload를 먼저 작성하였는데 출력된 결과물을 보면 window.addEventListener("DOMContentLoaded", listener)가 먼저 출력된 것을 확인할 수 있다. onload와 DOMContentLoaded는 결과적으로는 같은 기능을 수행하나 그 과정에서 조금의 차이가 있다. window.onload는 html 페이지, css 페이지, javascript 페이지 등 모든 페이지들의 로드가 끝난 다음에 실행되는 반면 DOMContentLoaded는 html의 로드만을 체크해서 html의 로드가 끝난 다음에 실행되게 된다. 그 결과 onload 방식보다 속도가 빨라 나중에 작성하였어도 먼저 출력되는 결과가 나타나는 것이다.
이상으로 window.onload와 window.addEventListener("DOMContentLoaded", listener) 방식에 대해 알아보았는데 요즘에는 주로 DOMContentLoaded를 사용해서 처리하는 추세이다. 트랜디한 개발자가 되고자 한다면 트랜드를 따라가는 것도 나쁘지 않다고 생각한다.
'JavaScript' 카테고리의 다른 글
JavaScript - 전역(global)변수 , 지역(local)변수 (0) | 2022.02.04 |
---|---|
JavaScript ES6 - 템플릿 리터럴 , 객체 리터럴 , 구조분해 할당 (0) | 2022.01.27 |
JavaScript - DOM (1) (0) | 2022.01.10 |
JavaScript - 콜백(callback) (0) | 2022.01.10 |
JavaScript - 얕은복사 , 깊은복사 (0) | 2022.01.07 |