그전에 javascript의 탄생 이유를 알아야 한다.
브라우저엔 렌더링 엔진(크롬, 사파리 등)이 있다.
렌더링 엔진이 html 문서를 렌더링(해석)한다.
해석이 왜 필요할까?
이유는 javascript가 서버로부터 받은 파일을 알아들을 수 없기 때문이다. 따라서 이해하기 쉽게 해석하는 과정이 필요하다.
렌더링 엔진이 HTML을 알아보기 좋게 DOM Tree, CSS를 CSSOM Tree로 만든다음 묶어서 Render Tree를 구성한다.
Render Tree ?
HTML, CSS 및 JavaScript 문서를 파싱(해석)해서 브라우저에 실제로 렌더링되는 최종 문서 모델을 나타내는 객체의 계층 구조이다.
Document(HTML)를 javascript가 이해하게 Object 형태로 Modeling 한 것.
따라서, 브라우저에게 DOM 객체를 접근할 수 있게 도와주는 것이기 때문에 API가 되는 것. 또한, DOM관련 여러 API가 존재한다.API란?
다른 시스템에 데이터나 서비스를 요청할 때, API는 해당 시스템과 사용자 간의 인터페이스 역할을 한다.
따라서, API는 다른 시스템에서 제공하는 기능을 사용할 수 있도록 도와주는 중간자 역할을 한다.
Node란?
HTML태그, text, 속성 등이 합쳐진 것을 블록으로 만든 것을 node라고 한다.
DOM node의 속성과 메소드
쉽게 얘기하자면 값이 속성, 동작을 수행하는게 메서드
document.getElementById('div').innerHTML = 'hi';
ES6에서 처음 도입된 개념
javascript는 객체지향언어다. 다른 언어에서 클래스 기반으로 프로그래밍을 한 개발자들에 의해 js에서도 class 개념이 도입되었다.
객체를 생성하기 위한 변수나 속성, 메서드의 템플릿.
class Person {
construtor(name, age){
this.name = name;
this.age = age;
}
sayHello() {
console.log(`hi I'm ${this.name}`);
}
}
//인스턴스 생성
const person1 = new Person("james");
person1.sayHello(); //hi I'm james
값을 가지고 set할 때 검증을 할 수 있다.
class Rectangle {
constructor(height, width) {
this._height = height; //private하게 사용하기위해 _를 쓴다
this._width = width;
}
get width() {
return this._width;
}
set width(value) {
//검증, 유효성 검사
if (value <= 0) {
console.log("error");
} else if (typeof value !== "number") {
console.log("enter the number");
return;
}
this._width = value;
}
get height() {
return this._height;
}
set height(value) {
//검증, 유효성 검
if (value <= 0) {
console.log("error");
} else if (typeof value !== "number") {
console.log("enter the number");
return;
}
this._height = value;
}
getArea() {
const a = this._width * this._height;
console.log(`넓이는 ${a}입니다.`);
}
}
//rec1의 너비와 높이 지정해줌
const rec1 = new Rectangle(10, 20);
//rec1의 넓이를 구하는 함수를 호출
rec1.getArea();
언더바를 쓰지않으면 콜스택이 꽉차서 불러오는데 문제가 있다.
//부모 클래스
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} say hi`);
}
}
//상속
class Dog extends Animal {
//부모에게 있는 메서드를 재정의 할 수 있음
//overRiding.
speak() {
console.log(`${this.name} barks!`);
}
}
const pupps = new Dog("long");
pupps.speak();
class Calculate {
static add(a, b) {
console.log("더하기: ");
return a + b;
}
static substr(a, b) {
console.log("빼기: ");
return a - b;
}
}
//이렇게 바로 class에서 메소드를 호출한다.
console.log(Calculate.add(3,5)); //8
클로저는 함수와 그 함수가 선언된 렉시컬 환경과의 조합이다.
const x = 1;
function outer() { //전역에 선언
const x = 10;
function inner() { //outer 안에서 선언
console.log(x); // 10이 나온다.
}
inner();
}
outer();
====================================
const x = 1;
function outer(){ //전역에 선언
const x = 10;
inner();
}
function inner(){ //전역에 선언
console.log(x); //1
}
outer();
위 코드를 봤을 때, JS는 함수를 호출한 scope(지역)보다 “선언”한 scope에 따라서 상위 스코프를 결정한다.
외부 함수보다 중첩 함수가 더 오래 유지 되는 경우(어디 호출된게 아직 안 끝남), 중첩 함수는 이미 생명 주기가 종료한 외부 함수의 변수를 여전히 참조할 수 있다.
아래 예시를 보자
const x = 1;
function outer() {
const x = 10;
const inner = function () {
console.log(x);
};
return inner;
}
const innerFunc = outer();
innerFunc();
[순서]
→ 이게 클로저다.
[가능한 이유]
클로저는 상태를 안전하게 변경하고 유지하기 위해 사용한다.
const increase = (function () {
//카운트 상태 변수
let num = 0;
//클로
return function() { //이 함수가 즉시실행되면서 increase에 할당
return ++num;
};
})();
console.log(increase()); //increase의 즉시실행함수는 사라졌지만
//상위 스코프를 기억하는 반환된 함수가 있다.
//num이 +1되고 그 변수를 소멸된 즉시실행 함수에 저장
//그러면 private한 변수가 되어서 increase를 사용할 때만 변경할 수 있는것.
[순서]