[JS 완벽 가이드] 웹 브라우저의 자바스크립트 (part1)

개발 log·2022년 7월 20일
0

JS 지식

목록 보기
31/36
post-thumbnail

15 | 웹 브라우저의 자바스크립트 (part1)

JavaScript는 웹 브라우저에 표시되는 문서에 동적인 동작을 부여하기 위한 목적으로 1994년에 개발되었다.

웹 브라우저는 형식화된 텍스트와 이미지를 표시할 의도로 개발됐지만 이제는 네이티브 운영 체제와 마찬가지로 그래픽, 비디오, 오디오, 네트워크, 스토리지, 스레드 같은 서비스도 제공한다.

웹 플랫폼이 제공하는 서비스를 웹 애플리케이션에서 사용하기 위해서는 JavaScript가 필요하다.

웹 프로그래밍 기본

클라이언트 사이드 JavaScript

클라이언트 사이드라는 용어가 자주 사용되는데, 이 용어는 웹 브라우저에서 실행하도록 작성한 JavaScript를 뜻하며, 웹 서버에서 실행되는 서버 사이드코드의 반대말이다.

클라이언트 사이드서버 사이드는 웹 브라우저와 웹 서버 사이에 있는 네트워크 연결의 양 극단이며 웹 소프트웨어를 개발할 때는 일반적으로 양쪽을 모두 개발해야한다.

  • 클라이언트 사이드: 프론트엔드
  • 서버 사이드: 백엔드

위 처럼 부르기도 한다.

구형 API

JavaScript가 처음 발표되고 25년이 흐르는 동안 브라우저 제조사에는 계속해서 새로운 기능과 프로그래머가 사용할 API를 추가해 왔다.

이 API 중에는 이제 쓸모없어진 것도 많다.

  • MS사의 IE는 표준화된적도 없고 다른 브라우저 제조사에서 구현한적도 없는 전용 API가 많다.
    • innerHTML 프로퍼티처럼 유용함이 증명되어 표준화된 것도 있지만 나머지는 대부분 오래전부터 아무도 사용하지 않는다.
  • document.write()메서드 같은 비효율적인 API는 성능에 심각한 영향을 주므로 사용해서는 안된다.
  • 브라우저 제조사는 앞으로 얼마간은 하위 호환성을 유지하기 위해 구형 API를 지원하겠지만 앞서말한대로 이미 구축된 웹의 하위 호환성을 위해서 지원할뿐이니 깊게 생각할 필요는 없다.

웹 프로그래밍 기본

이 절에서는 아래와같은 내용을 다룬다.

  • 웹에서 JavaScript 프로그램을 구성하는 방법
  • 웹 브라우저로 불러오는 방법
  • JavaScript 프로그램이 입력을 받고 출력하는 방법
  • 이벤트에 반응해 비동기적으로 실행되는 방법

HTML <script>태그 속의 자바스크립트

웹 브라우저는 HTML 문서를 표시한다. 웹 브라우저에서 JavaScript 코드를 실행하려면 반드시 그 코드를 HTML문서에 포함 또는 참조해야하는데 이 역할을 수행하는 태그가 <script>태그이다.

자바스크립트 코드를 사용하는 방법 2가지

  • <script></script>태그 사이에 인라인으로 작성하는 방법
  • <script>태그의 src 속성을 사용하여 파일의 URL을 지정하는 방법

주의사항: <script>태그는 <script/> 즉 셀프 클로징을 지원하지 않는다.

반드시 <script></script>형태로 작성해야 한다.

src 속성의 장점

  • 방대한 JavaScript 코드를 HTML 파일에서 제거하여 단순화한다. (즉, 내용과 동작을 분리한다.)
  • 여러개의 웹 페이지에서 같은 JavaScript 코드를 공유할 때 src속성을 쓰면 코드를 한 파일로만 관리하면 된다.
  • JavaScript 코드를 여러 페이지에서 공유한다면 한 번만 내려받으면 된다.
    • 첫번째 페이지에서 코드를 내려받으면 다른 페이지는 브라우저 캐시에서 가져올 수 있다.
  • src속성은 임의의 URL을 값으로 받으므로 한 서버에 있는 JavaScript 프로그램이나 웹 페이지가 다른 웹 서버에 있는 코드를 가져올 수 있다.
    • 인터넷 광고는 대부분 이를 바탕으로 만들어진다.

모듈

만약 JavaScript 프로그램을 모듈로 작성했다면 (그리고 코드 번들링 도구를 써서 모듈을 하나의 JavaScript 파일로 조합하지 않았다면) 반드시 최상위 모듈을 <script type="module">태그로 불러와야 한다.

이렇게 하면 지정한 모듈을 불러오고, 그 모듈의 import 모듈을 모두 불러오고 재귀적으로 다시 가져온 모듈을 불러온다.

스크립트 타입 지정

웹 초기에는 언젠가 브라우저에서 JavaScript가 아닌 다른 언어가 스일 것을 염두에 두고 <script>태그에 language="javascript", type="application/javascript"속성을 추가했었다.

하지만 JavaScript는 현대에 새로 등장한 (pyscript)를 제외하고 오랜 기간동안 웹의 기본 언어이기 때문에 language속성은 폐기 되었다.

<script>태그에 type속성을 사용하는 경우

  • 스크립트가 모듈일 때
  • 웹 페이지가 데이터를 가져오지만 표시하지는 않을 때

스크립트 실행 시점: asyncdefer

웹 브라우저가 JavaScript를 처음 도입했을 때 이미 렌더링된 문서의 구조와 콘텐츠를 조작하고 문서 간에 이동할 수 있는 API는 존재하지 않았다.

JavaScript 코드가 문서 콘텐츠에 영향을 주는 방법은 문서를 불러오고 있는 동안 즉석에서 콘텐츠를 생성하는 것, 즉 document.write() 메서드를 사용해 스크립트 위치에 HTML 텍스트를 주입하는 것뿐이었다.

현재 document.write()는 폐기됐지만, document.write()가 이런 식으로 동작한다는건 HTML 파서에 <script>요소를 만날때마다 반드시 그 스크립트를 실행해 HTML을 출력하지 않음을 확인한 후에야 문서 분석과 렌더링을 재개할 수 있다는 의미이다.

이렇게 <script>요소를 만날때마다 반드시 스크립트를 실행해 HTML을 출력하는지 여부를 확인하는 방식은 웹 페이지 분석과 렌더링 속도를 심하게 저해하기 때문에 document.write()가 폐기되었다고 생각한다.

다행인 것은 스크립트의 기본 모드인 동기적모드가 유일한 모드는 아니라는 것이다.

<script>태그에 defer, async 속성을 사용해서 스크립트 실행방식을 바꿀 수 있다.

이 두 속성을 boolean값을 가진 속성이고 단, src 속성과 함께 사용해야만 의미가 있다.

<script defer src="deferred.js"></script>
<script async src="async.js"></script>

defer, async 속성은 모두 연결된 스크립트에 HTML을 만드는 document.write()가 없으므로 브라우저가 스크립트를 다 내려받을 때가지 기다리지 않고 문서 분석과 렌더링을 계속해도 된다.

defer

defer속성은 문서를 완전히 내려받고 분석해서 조작할 준비가 끝날 때까지 스크립트 실행을 지연(defer)하라는 의미이다.

async

async속성은 브라우저가 스크립트를 가능한 빨리 실행하되 스크립트를 내려받는 동안 문서 분석을 계속해도 된다는 뜻이다.

만약 <script>태그에 두 속성이 모두 존재한다면 async속성이 우선순위를 갖는다.

지연된(defer) 스크립트는 문서 출처 순서대로 실행된다. 비동기(async) 스크립트는 불러오는 즉시 실행되므로 문서 출처대로 실행되지 않을 수 있다.

type="module"속성이 있는 스크립트는 기본적으로 defer속성이 있는 것처럼 문서 로딩이 끝난 후 실행된다.

async 속성을 사용하면 문서 로딩이 끝날때까지 대기하지 않고 가져온 모듈 전부를 불러오는 즉시 실행한다.

async, defer 속성을 사용하지 않고 스크립트는 HTML파일 마지막에 불러오기만 해도 같은 효과를 볼 수 있다.

필요에 다른 스크립트 로드

문서를 처음 불러올 때는 필요없지만 사용자가 버튼을 클릭하거나 메뉴를 여는 등 어떤 행동을 했을때만 필요한 JavaScript 코드도 있다.

모듈을 사용해 코드를 개발했다면 import()를 사용해 필요한 모듈만 불러올 수도 있다.

모듈을 사용하지 않는다면 스크립트를 불러올 때 문서에 <script>태그를 추가해서 JavaScript 파일을 불러올 수 있다.

// 지정된 URL에서 비동기적으로 스크립트를 불러와서 실행합니다.
// 스크립트를 불러오면 해석되는 프라미스를 반환합니다.
function importScript(url) {
  return new Promise((resolve, reject) => {
    let 5 = document.createElement("script"); // <script> 요소 생성
    s.onload = () => { resolve(); }; // 프라미스 해석
    s.onerror = (e) => { reject(e); }; // 실패 시 거부
    s.src = url; // 스크립트 URL 설정
    document.head.append(s); // 문서에 <script> 추가
  }) ;
}

문서 객체 모델

Document객체는 브라우저 창이나 탭에 표시되는 HTML 문서를 나타내는 객체이며 클라이언트 사이드 JavaScript 프로그래밍에서 가장 중요한 객체 중 하나이다.

HTML 문서를 다루는 API를 문서 객체 모델 또는 DOM이라 부른다.

HTML은 요소가 서로 중첩되어 트리 구조를 형성한다. 아래 HTML문서를 보자

<html>
  <head>
    <title>Sample Document</title>
  </head>
  <body>
    <h1>An HTML Document</h1>
    <p>This is a <i>simple</i> document.</p>
  </body>
</html>

HTML 문서의 트리 구조

DOM API에는 새로운 Element, Text 노드를 생성하고 이들을 다른 Element 객체의 자식으로 문서에 삽입하는 메서드가 있다. 또, 문서 내에서 요소를 이동하거나, 완전히 제거하는 메서드도 있다.

대부분의 JavaScript 요소 클래스는 HTML 태그 속성을 반영할 뿐이지만 일부는 추가로 메서드를 정의하기도 한다.

예를 들어 HTMLAudioElementHTMLVideoElement 클래스에는 오디오, 비디오 파일의 재생을 제어하는 play(), pause()같은 메서드가 있다.

웹 브라우저의 전역 객체

브라우저 창이나 탭마다 이에 대응하는 전역 객체가 하나씩 있다.

워커 스레드를 제외한 모든 JavaScript 코드는 전역 객체를 공유한다.

문서에 스크립트나 모듈이 얼마나 많은지는 관계가 없다.

스크립트에서 전역 객체에 프로퍼티를 정의하면 그 프로퍼티는 다른 스크립트 전체에서 볼 수 있다.

JavaScript의 표준 라이브러리는 전역 객체에 정의된다. 웹 브라우저에서 전역 객체는 다양한 웹 API의 진입점이기도 하다.

예를 들어 document 프로퍼티는 현재 문서를 나타내고 fetch()메서드는 HTTP 네트어크 요청을 보내며 Audio()생성자는 JavaScript 프로그램에서 사운드를 재생한다.

웹 브라우저에서 전역 객체는 두가지 임무를 수행한다.

전역 객체는 내장 타입과 함수를 정의하기도 하지만 웹 브라우저 창을 나타내기도 하며 그 창의 브라우징 히스토리를 나타내는 history, 창의 너비를 픽셀로 나타내는 innerWitdh같은 프로퍼티를 정의하기도 한다.

이 전역 객체에는 window 프로퍼티가 있으며 그 값은 전역 객체 자체이다.

따라서 클라이언트 사이드 코드에서 window를 입력해 전역 객체를 찹조할 수 있다.

전역 객체와 관련된 기능을 사용할 때는 앞에 window.를 붙이는 편이 좋다.

네임스페이스를 공유하는 스크립트

모듈의 최상위 레벨, 즉 다른 함수나 클래스 정의, 바깥에서 정의한 상수, 변수, 함수, 클래스는 명시적으로 내보내지 않는 한 그 모듈에서만 사용하는 비공개(private)변수이다.

하지만 모듈이 아닌 스크립트에서는 같은 문서에서 실행된 모든 스크립트에서 최상위 코드에 정의된 상수, 변수, 함수, 클래스를 볼 수 있다.

이는 볼륨이 큰 프로그램에서 겹치는 이름을 피하는 일만으로도 고역일 수 있고, 서드 파티 라이브러리를 사용한다면 네임스페이스로 인해 많은 문제를 겪을 수 있다.

하지만 모듈의 최상위 선언은 그 모듈을 스코프로 가지기 때문에 안전하게 관리할 수 있다.

자바스크립트 프로그램 실행

클라이언트 사이드 JavaScript에는 프로그램을 공식적으로 정의하고 있지 않지만, 문서에 존재하거나 문서를 참조하는 JavaScript 코드가 모여 JavaScript 프로그램이 된다고 할 수 있다.

만약 웹 페이지에 <iframe>요소로 임베드된 프레임이 있다면 해당 임베드된 문서의 JavaScript 코드는 임베드한 문서와는 다른 전역 객체와 Document 객체를 가지므로 별도의 JavaScript 프로그램이라고 볼 수 있다.

하지만 앞서 말했듯 JavaScript 프로그램의 경계를 정하는 공식 정의는 없다.

JavaScript 프로그램은 두 단계로 실행된다고 생각해도 무방하다.

첫 번째 단계에서는 문서 콘텐츠를 불러오고 <script>요소의 코드를 실행한다.

스크립트는 일반적으로 문서 순서대로 실행되지만, async, defer 속성에 의해 순서가 바뀔 수 있다.

스크립트에 포함된 JavaScript 코드는 위쪽에서 아래쪽으로 실행되지만, JavaScript의 조건문, 루프, 기타 제어문에 의해 순서가 바뀔 수 있다.

일부 스크립트는 첫번째 단계에서 거의 아무일도 하지 않고 두번째 단계에 사용할 함수와 클래스를 정의하기만 한다.

또, 어떤 스크립트에서는 첫번째 단계에서만 동작하고 두번째 단계에서는 아무것도 하지 않는다.

문서 로딩이 끝나고 스크립트를 전부 실행하면 JavaScript는 두번째 단계에 들어가며 이 단계는 비동적이고 이벤트 주도적이다.

이벤트 주도적인 두번째 단계에서 웹 브라우저는 비동기적으로 일어나는 이벤트에 응답해 이벤트 핸들러나 기타 콜백을 호출한다.

이벤트 핸들러는 대부분 마우스 클릭이나 키 입력 중 사용자의 입력에 응답하지만 네트워크 활동, 문서나 자원 로딩, 경과한 시간, JavaScript 코드의 에러 등으로도 호출될 수 있다.

두번째 단계에서 처음 일어나는 이벤트에는 DomContentLoadedload이벤트가 있다.

DomContentLoaded

DomContentLoaded이벤트는 HTML문서의 로딩과 분석이 완전히 끝났을 때 발생한다.

load

load이벤트는 이미지 같은 문서의 외부 자원을 완전히 불러왔을 때 발생한다.

JavaScript 프로그램의 첫번째 단계는 비교적 짧으며 1초 안에 이루어지는 것이 이상적이다.

문서 로딩이 끝나면 문서가 웹 브라우저에 표시되는 동안 이벤트 주도적인 두번째 단계가 계속 이어진다.

이 단계는 비동기적이고 이벤트 주도적이므로 오랫동안 아무 활동도 없다가 특정 상호작용에 의해 갑자기 활동하는 경우도 있다.

클라이언트 사이드 자바스크립트 스레드 모델

JavaScript는 싱글 스레드 언어이며, 싱글 스레드 실행 모델은 두 이벤트 핸들러가 절대 동시에 실행되지 않으므로 프로그래밍이 훨씬 단순하다.

콘텐츠를 수정할 때 다른 스레드가 같은 콘텐츠를 동시에 수정하게 될 일도 없고 락(lock), 교착 상태(deadlock), 경합 조건(race condition)을 걱정할 필요도 없다.

싱글 스레드는 웹 브라우저가 스크립트와 이벤트 핸들러를 실행하는 동안 사용자 입력에 반응하지 않는다는 의미이다(blocking때문!)

따라서 JavaScript 프로그래머는 스크립트와 이벤트 핸들러가 너무 오래 실행되게 만들어서는 안된다.

웹 플랫폼은 웹 워커를 통해 동시성을 구현한다.

웹 워커는 사용자 인터페이스를 멈추지 않으면서 실행되는 백그라운드 스레드이다.

웹 워커 스레드에서 실행되는 코드는 문서 콘텐츠에 접근할 수 없고, 메인 스레드나 다른 워커와는 상태를 공유하지 않으면서 오직 비동기 메시지 이벤트를 통해서만 통신한다.

메인 스레드는 이런 동시성을 인지하지 못하므로 웹 워커는 JavaScript 프로그램의 싱글 스레드 실행 모델을 망치지 않는다.

클라이언트 사이드 자바스크립트 타임라인

  1. 웹 브라우저가 Document 객체를 생성하고 웹 페이지 분석을 시작하고, HTML 요소와 텍스트 콘텐츠를 분석할 때마다 Element 객체와 Text 노드를 문서에 추가한다.(이 단계에서 document.readyState프로퍼티 값은 loading이다.)
  2. HTML 파서가 async, defer, type="module"속성이 없는 <script>태그를 만나면 스크립트 태그를 문서에 추가하고 스크립트를 실행한다.
  3. 문서 분석이 완전히 끝나면 document.readyState 프로퍼티가 interactive로 변경된다.
  4. defer속성이 있는 스크립트, async속성이 없는 모듈 스크립트는 문서 순서대로 실행된다.(async 스크립트도 언제 실행되는지는 알수 없으므로 이때 실행될수도 있다.)
  5. 브라우저가 Document 객체에서 DOMContentLoaded 이벤트를 발생시킨다.
  6. 이 시점에서 문서 분석은 완전히 끝났지만 브라우저는 여전히 이미지같은 콘텐츠를 기다리고 있을 수 있다, 콘텐츠 로딩이 끝나고 async스크립트 로딩과 실행도 끈나면 document.readyState프로퍼티는 complete로 바뀌고 웹 브라우저는 window객체에서 load이벤트를 발생시킨다.
  7. 이 시점부터 사용자의 입력 이벤트, 네트워크 이벤트, 타이머 종료 등에 의해 이벤트 핸들러가 비동기적으로 호출된다.

프로그램 입출력

다른 프로그램과 마찬가지로 클라이언트 사이드 JavaScript 프로그램도 입력 데이터를 처리해 출력 데이터를 만든다.

  • JavaScript 코드에서 DOM API를 통해 접근할 수 있는 문서 콘텐츠 자체
  • 이벤트 형태인 사용자 입력 <button> 클릭 및 터치 스크린 탭 등등
  • 문서 URL: document.URL
  • 쿠키 요청 헤더 콘텐츠: document.cookie
  • 전역 navigator 프로퍼티를 통해 웹 브라우저, 운영 체제와 그 기능에 접근 가능
    • navigator.userAgent: 웹 브라우저를 식별하는 문자열
    • navigator.language: 사용자가 선호하느 언어
    • navigator.hardwareConcurrency: 웹 브라우저가 사용할 수 있는 논리적 CPU 개수

웹 보안 모델

웹 페이지에서 방문자 개인의 장치에 임의의 JavaScript 코드를 실행할 수 있다는 것은 보안에 큰 영향을 주기 때문에 브라우저 제조사들은 아래 두 가지 상반되는 목표간의 균형을 맞추기 위해 노력해왔다.

  • 유용한 웹 애플리케이션을 사용할 수 있는 강력한 클라이언트 사이드 API를 정의하는 것
  • 악의적인 코드에서 데이터를 읽거나 수정하지 못하게 하고, 개인 정보에 접근하지 못하게 방지하는 것

자바스크립트에서 할 수 없는 일

악의적인 코드에 대한 웹 브라우저의 첫번째 방어선은 특정 기능을 지원하지 않는 것

  • 클라이언트 사이드 JavaScript는 클라이언트 컴퓨터의 디렉터리를 읽을 수 없고 파일 수정 삭제도 불가능하다.

    덕분에 클라이언트 사이드 JavaScript 프로그램은 데이터를 삭제하거나 바이러스를 옮길 수 없다.

  • 범용 네트워크 기능도 없다.

클라이언트 사이드 JavaScript 프로그램은 HTTP 요청을 보낼 수 있고 웹 소켓이라는 표준도 있지만 어느 API도 방대한 네트워크에 제한 없이 접근하도록 허용하지는 않는다.

덕분에 클라이언트 사이드 JavaScript로 범용 인터넷 클라이언트와 서버를 만들 수는 없다.

동일 출처 정책(same-origin policy)

JavaScript 코드에서 접근할 수 있는 웹 콘텐츠를 제어하는 보안 제한

스크립트는 자신을 포함한 문서와 같은 서버에서 가져온 창과 문서의 프로퍼티만 읽을 수 있다.

  • 스크립트 자체의 출처는 동일 출처 정책과 관련이 없다.
  • 문제가 되는 것은 스크립트를 포함한 문서의 출처

교차 출처 간 자원 공유(Cross-Origin Resource Sharing)

CORS는 HTTP를 Origin: 요청 헤더와 Access-Control-Allow-Origin을 응답헤더로 확장한다.

브라우저는 CORS 헤더를 지원하며 이 헤더가 존재하지 않으면 동일 출처 제한을 완화하지 않는다.

교차 사이트 스크립트

교차 사이트 스크립트(Cross-site scripting)(XSS)는 공격자가 대상 웹사이트에 HTML 태그나 스크립트를 주입하는 보안 문제를 통틀어 가리키는 용어

클라이언트 사이드 JavaScript 프로그래머는 반드시 교차 사이트 스크립트를 염두에 두고 방어해야 한다.

이벤트

클라이언트 사이드 JavaScript 프로그램은 비동기적인 이벤트 주도 프로그래밍 모델을 사용한다.

웹 브라우저는문서, 브라우저, 요소, 객체에 뭔가 흥미로운 일이 일어날 때마다 이벤트를 발생시킨다.

이벤트 타입

이벤트 종류를 지정하는 문자열

이벤트 대상

이벤트가 일어난, 또는 이벤트와 연관된 객체

이벤트 핸들러 또는 이벤트 리스터

이 함수는 이벤트를 처리하거나 이벤트에 반응한다.

  • 애플리케이션은 이벤트 타입과 이벤트 대상을 지정해 웹 브라우저에 이벤트 핸들러 함수를 등록한다.
  • 지정된 대상에서 지정된 타입의 이벤트가 일어나면 브라우저가 핸들러 함수를 호출한다.

이벤트 객체

이벤트에 대한 세부 정보를 포함하고 있다.

  • 이벤트 객체는 이벤트 핸들러 함수에 인자로 전달된다.
  • 모든 이벤트 객체에는 이벤트 타입을 나타내는 type 프로퍼티, 이벤트 대상을 나타내는 target프로퍼티가 있다.

이벤트 전달

브라우저는 이 프로세스를 통해 어떤 객체에서 이벤트 핸들러를 호출할지 결정한다.

  • HTML 문서의 요소에서 일어나는 일부 이벤트는 문서 트리를 따라 전달된다.
  • 이벤트 핸들러에서 이벤트 전달을 차단해 포함하는 요소의 핸들러를 호출하지 못하게 막을 수 있다.
  • 이벤트 캡처링이라 부르는 또 다른 형태의 이벤트 전달에서는 컨테이너 요소에 등록된 핸들러가 이벤트가 실제 대상에 전달되기 전에 캡처할 기회를 갖는다.

이벤트 핸들러 등록

이벤트 핸들러 프로퍼티 설정

// Window 객체의 onload 프로퍼티를 할수로 설정합니다.
// 이 함수가 이벤트 핸들러이며 문서를 불러올 때 호출됩니다.
window.onload = function() {};

// <form> 요소를 찾습니다.
let form = document.querySelector("form#shipping'’);

// 폼을 전송하기 전에 호출될 이벤트 핸들러 함수를 등록할니다.
// isFormValid() 는 다른 곳에서 정의했다고 가정합니다.
form.onsubmit = function(event) { // 사용자가 폼을 전송할 때
  if (lisFormValid(this)) {       // 폼 입력이 유효한지 체크합니다.
    event.preventDefault();       // 유효하지 않다면 폼 제출을 막습니다.
  }
}

이벤트 핸들러 속성 설정

<button onclick="console. log('Thank you');">Please Click</button>

addEventListener()

addEventListener()는 인자 세개를 받는다.

  1. 핸들러를 등록할 이벤트 타입
  2. 호출될 콜백함수
    3.1. boolean값: 캡처링 여부(true이면 캡처링 이벤트 핸들러로 등록하는 것)
    3.2. 객체값: 옵션값(capture, once, passive...)
<button id="mybutton">Click me</button>
<script>
  let b = document.querySelector('#mybutton');
  b.onclick = function () {
    console.log('Thanks for clicking me!');
  };
  b.addEventListener('click', () => {
    console.log('Thanks again!');
  });
</script>

addEventListener()의 특징은 중복 등록이 가능하다는 것이고, 이를 제거하기 위해서는 removeEventListener()메서드를 사용해야 한다.

문서 스크립트

클라이언트 사이드 JavaScript의 목적은 정적인 HTML문서를 대화형 웹 애플리케이션으로 바꾸는 것

따라서 웹 페이지의 콘텐츠를 변경하는 것이야말로 JavaScript의 원래 목적이다.

문서 요소 선택

CSS 선택자로 요소 선택

let spinner = document.querySelector('#spinner');
let hyperLink = event.target.closest('a[href]');

문서 구조와 순회

문서에서 요소를 선택한 뒤 그 요소와의 관계를 통해 부모, 형제, 자식 요소를 찾아야 할때도 있다.

parentNode

요소의 부모를 참조(Element | Document)

children

이 노드리스트는 요소의 자식인 요소를 포함하지만, 요소가 아닌 자식인 Text노드와 Comment노드는 제외한다.

childElementCount

자식 요소 개수 === children.length

firstElementChild, lastElementChild

요소의 자식 중 첫 번째와 마지막을 각각 참조, 없다면 null

nextElementSibling, previousElementSibling

요소의 바로 앞이나 바로 다음에 있는 형제 요소를 참조하며 그런 형제가 없다면 null

profile
프론트엔드 개발자

0개의 댓글