객체는 상태를 나타내는 ‘프로퍼티’와 동작을 나타내는 ‘메서드’를 하나로 묶은 자료 구조다.
메서드는 자신이 속한 객체의 상태를 참조하고 변경할 수 있어야 하는데 ((ex) getter, setter…) 그러려면 자신이 속한 객체를 참조할 수 있어야 한다.
→ 이 역할을 하는 게 this!
This는 자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수다. 이를 통해 프로퍼티나 메서드를 참조할 수 있다.
This는 자바스크립트 엔진에 의해 암묵적으로 생성되고, 코드 어디서든 참조할 수 있다. this가 가리키는 값이 연결되는 this 바인딩은 함수 호출 방식에 의해 동적으로 결정된다.
💡 function 함수와 화살표 함수의 this 차이
= 자바스크립트가 실행되는 환경. 자바스크립트가 실행될때, 실행 컨텍스트는 변수, 함수 선언, 스코프 등 관련된 정보를 담고 있다.
실행 컨텍스트는 자바스크립트의 동작 원리를 담은 핵심 개념이다.
<소스 평가 과정과 실행 과정>
자바스크립트는 소스 코드에 따라 실행 컨텍스트를 실행한다. (전역 코드, 함수 코드, eval 코드, 모듈 코드)
자바스크립트는 소스코드 실행 전에 소스코드 평가 과정을 거친다. 소스코드 평가 과정에선 실행 컨텍스트를 생성하고, 변수와 함수 등의 선언문만 먼저 실행되어 생성된다.
→ 이로 인해 생성된 변수나 함수 등을 실행 컨텍스트가 관리하는 스코프 (렉시컬 환경의 환경 레코드)에 등록한다.
그 이후에 선언문을 제외한 소스코드가 순차적으로 실행된다. (런타임). 이 때 소스코드 실행에 필요한 변수나 함수 같은 정보를 실행 컨택스트가 관리하는 스코프에서 가져온다.
소스코드의 실행 결과는 다시 실행 컨택스트가 관리하는 스코프에 등록된다.
<실행 컨텍스트의 역할>
클로저에 대해서 아나요? 🔥🔥
클로저는 자바스크립트 뿐만 아니라 함수를 일급 객체로 취급하는 함수형 프로그래밍 언어에서 사용되는 중요한 특성.
클로저는 “함수와 그 함수가 선언된 렉시컬 환경과의 조합이다”
중첩 함수는 자신을 포함하고 있는 외부함수(상위 스코프)의 변수에 접근할 수 있다 → 클로저
렉시컬 스코프: 자바스크립트 엔진은 함수를 어디서 호출했는지가 아니라 함수를 어디서 정의했는지에 따라 상위 스코프를 결정한다. 이를 렉시컬 스코프(정적 스코프)라고 한다.
이 렉시컬 스코프는 “외부 렉시컬 환경에 대한 참조”에 저장될 참조 값이다. 함수 정의가 평가되는 시점 (소스 평가 과정) 에 함수가 정의된 환경에 의해 결정된다. 함수는 자신의 내부 슬롯 [[Environment]]에 자신이 정의한 환경인 상위 스코프의 참조를 저장한다.
이 Environment에 저장된 값 = 실행 중인 실행 컨텍스트의 렉시컬 환경의 참조 = 상위 스코프 = 외부 렉시컬 환경에 대한 참조에 저장될 참조값
클로저를 사용하면 뭐가 좋죠? 🔥
💡 어디까지 기억할까?
💡 클로저가 함수다?
// 생성자
constructor(name) {
this.name = name;
}
// 프로토타입 메서드
sayHi() {
console.log('Hi!')
}
// 정적 메서드
static sayHello() {
console.log('Hello!');
}
상속은 코드 재사용 관점에서 매우 유용하다
프로토타입 기반 상속은 프로토타입
체인을 통해 다른 객체의 자산을 상속받는 개념
상속에 의한 클래스 확장은 기존 클래스를 상속받아 새로운 클래스를 확장하여 정의하는 개념, extends 키워드를 사용한다.
상속으로 인해 확장된 클래스를 sub class라고 부르고, sub class에게 상속된 클래스를 super class라고 부른다.
→ 수퍼클래스와 서브클래스는 인스턴스의 프로토타입 체인뿐 아니라 클래스 간의 프로토타입 체인도 생성한다. 이를 통해 프로토타입 메서드, 정적 메서드 모두 상속이 가능하다
가능한 대상
Array, String, Map, Set, DOM 컬렉션(NodeList, HTMLCollection), arguments와 같이 for... of 문으로 순회할 수 있는 이터러블에 한정된다
💡 이터러블이란?
*반복 가능한(iterable, 이터러블)* 객체는 배열을 일반화한 객체입니다.
이터러블 이라는 개념을 사용하면 어떤 객체에든 for..of 반복문을 적용할 수 있습니다.
메서드 Symbol.iterator가 구현된 객체여야 하며,
대표적으로 배열과 문자열이 있다
스프레드 문법의 결과물은 값으로 사용할 수 없고 쉼표로 구분한 값의 목록(배열, 가변인자 등…)을 사용하는 문맥에서 사용할 수 있다.
1) 함수 호출문의 인자
2) 배열 리터럴 내부
3) 객체 리터럴 내부
💡 rest
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>브라우저 렌더링 예시</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #f0f0f0;
}
</style>
</head>
<body>
<main>
<section>
<h2>JavaScript 예시</h2>
<p id="message">버튼을 클릭하세요!</p>
<button id="clickButton">클릭하기</button>
</section>
</main>
**<script>
document.getElementById('clickButton').addEventListener('click', function() {
document.getElementById('message').textContent = '버튼이 클릭되었습니다!';
});
</script>**
</body>
</html>
DOM TREE, CSSOM TREE → RENDERING TREE → LAYOUT → PAINTING → REFLOW → REPAINT
1) 브라우저는 HTML, CSS, JAVASCRIPT, 이미지, 폰트 등 렌더링에 필요한 리소스를 요청하고 서버로부터 응답을 받는다.
2) 브라우저의 렌더링 엔진은 서버로부터 응답된 HTML과 CSS를 파싱하여 DOM과 CSSOM을 생성하고 이들을 결합하여 렌더 트리를 생성한다.
3) 브라우저의 자바스크립트 엔진은 서버로부터 응답된 자바스크립트를 파싱하여 AST(Abstract Syntax Tree)를 생성하고 바이트코드로 변환하여 실행한다. 이때 자바스크립트는 DOM API를 통해 DOM이나 CSSOM을 변경할 수 있다. 변경된 DOM과 CSSOM은 다시 렌더 트리로 결합된다
4) 렌더 트리를 기반으로 HTML 요소의 레이아웃(위치와 크기)을 계산하고 브라우저 화면에 HTML 요소를 페인팅한다.
자바스크립트 파싱하여 AST를 생성, 바이트 코드로 변환하여 실행.
dom api를 통해 dom이나 cssom을 변경할 수 있다.
변경된 dom과 cssom은 다시 렌더 트리로 결합됨
→ 브라우저는 해당 동작을 동기적으로 실행. js 파싱을 하면 html 파싱을 중단한다.
<script></script>
태그를 <body></body>
태그 밑에 둬야하는 이유가 있을까요?+) 모든 노드 객체는 Object, EventTarget, Node 인터페이스를 상속받는다.
추가적으로 문서 노드는 Document, HTMLDocument 인터페이스를 상속받고 어트리뷰트 노드는 Attr, 텍스트 노드는 CharacterData 인터페이스를 각각 상속받는다
💡 createTextNode는 언제 쓰지?
브라우저는 처리해야 할 특정 사건이 발생하면, 이를 감지하여 이벤트를 발생시킨다. (ex 마우스 이동, 클릭, 키보드 입력)
특정 이벤트가 일어났을 때 특정 작업을 하고 싶다면? 특정 이벤트가 일어났을 때 호출될 함수를 브라우저에게 알려 호출을 위임한다.
이 때 호출될 함수를 핸들러 handler 라고 한다. 이벤트 발생 시의 함수의 호출을 위임하는 것을 이벤트 핸들러 등록이라고 한다.
→ 이와 같이 프로그램의 흐름을 이벤트 중심으로 제어하는 프로그래밍 방식을 이벤트 드리븐 프로그래밍 event-driven programming이라 한다.
이벤트 핸들러 어트리뷰트 방식
이벤트 핸들러 프로퍼티 방식
addEventListener
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>이벤트 핸들러 등록 방식</title>
</head>
<body>
<!-- 이벤트 핸들러 어트리뷰트 방식 -->
<button onclick="handleClick1()">어트리뷰트 방식 클릭</button>
<!-- 이벤트 핸들러 프로퍼티 방식 -->
<button id="myButton2">프로퍼티 방식 클릭</button>
<!-- addEventListener 방식 -->
<button id="myButton3">addEventListener 방식 클릭</button>
<script>
// 이벤트 핸들러 어트리뷰트 방식
function handleClick1() {
alert('어트리뷰트 방식 버튼이 클릭되었습니다!');
}
// 이벤트 핸들러 프로퍼티 방식
var button2 = document.getElementById('myButton2');
button2.onclick = function() {
alert('프로퍼티 방식 버튼이 클릭되었습니다!');
};
// addEventListener 방식
var button3 = document.getElementById('myButton3');
button3.addEventListener('click', function() {
alert('addEventListener 방식 버튼이 클릭되었습니다!');
});
</script>
</body>
</html>
💡 버블링: 하위 → 상위
💡 phase는 하나만 가질 수 있다??
💡 캡처링 찾아내기 → 버블링
이벤트가 발생하는 phase가 보통 버블링이랑 타깃…
capturing을 true로 주면 버블링 단계에서 실행될게 캡쳐링 단계에서 실행된다.
자바스크립트 엔진은 단 하나의 실행 컨텍스트 스택을 갖는다. 이는 함수를 실행할 수 있는 창구가 단 하나이며. 동시에 2개 이상의 함수를 동시에 실행할 수 없다는 것을 의미한다.
대기 중인 태스크들은 현재 실행 중인 실행 컨텍스트가 팝되어 실행 컨텍스트 스택에서 제거되면. 다시 말해 현재 실행 중인 함수가 종료하면 비로소 실행되기 시작한다
그러므로 블로킹이 발생한다.
이벤트 루프
콜스택
마이크로태스트 큐 (더 우선순위를 가짐) - 프로미스 후속 처리 메서드
매크로 태스크 - 이벤트 핸들러, 비동기 함수의 콜백 함수
태스크 처리에 긴 시간이 걸리면, 브라우저는 태스크를 처리하는 동안에 발생한 사용자 이벤트 등의 새로운 태스크를 처리하지 못한다.
그렇기 때문에 항상 마이크로 태스크의 작업이 더 먼저 처리된다.
매크로 태스트: dom 이벤트 콜백, 타이머
마이크로 태스크
자바스크립트를 이용하여 브라우저가 서버에게 비동기 방식으로 데이터를 요청하고 서버가 응답한 데이터를 수신하여 웹 페이지를 동적으로 갱신하는 프로그래밍 방식
브라우저에서 제공하는 XMLHTTPREQUEST 객체를 기반으로 동작한다
모듈(module)이란 애플리케이션을 구성하는 개별적 요소로서 재사용 가능한 코드 조각을 말한다.
→ 자바스크립트는 원래 제한적인 기능을 제공학 위해 만든 언어여서 모듈을 신경 쓸 필요가 없었음.
→ 하지만 자바스크립트의 사용처가 넓어지면서 모듈이 필요해짐
→ CommonJS로 모듈 시스템이 표준화됨
💡 모듈 레벨 스코프
동일한 모듈이 여러곳에서 사용되더라도 모듈은 최초 호출 시 한번만 실행된다.
모듈 최상위 레벨의 this는 undefined
모듈 스크립트는 항상 지연 실행된다. 마치 defer 속성을 붙인 것처럼. 따라서 모듈 스크립트는 항상 완성된 페이지를 확인할 수있다.