DOM(Document Object Modeling)
- HTML 문서의 계층적 구조와 정보를 표현하며 이를 제어할 수 있는 API, 즉 프로퍼티와 메서드를 제공하는 트리 자료구조
브라우저 환경에서 확인 할 수 있다. Node환경에서는 확인 불가능 - 브라우저에 내장되어 있기 때문에 HTML 내용을 javascript로 접근, 제어 가능
- 모든 요소와 요소의 어트리뷰트, 텍스트를 각각의 객체로 만들고 이들 객체를 부자 관계를 표현할 수 있는 트리 구조
- 모든 DOM의 node들은 '속성'과 '메서드'를 갖고있음
- Node 객체의 속성은 값
=> 해당 객체의 특성을 나타내는 값을 가져오거나 설정 - 메서드는 동작을 수행
=> 해당 객체가 수행하는 작업을 나타내는 함수
- Node 객체의 속성은 값
//Finding
// 해당 id명을 가진 요소 하나를 반환합니다.
document.getElementById("id명")
// 해당 선택자를 만족하는 요소 하나를 반환합니다.
document.querySelector("선택자")
// 해당 class명을 가진 요소들을 배열에 담아 인덱스에 맞는 요소를 반환합니다.
document.getElementsByClassName("class명")[인덱스]
// 해당 태그명을 가진 요소들을 배열에 담아 인덱스에 맞는 요소를 반환합니다.
document.getElementsByTagName("태그명")[인덱스]
// 해당 선택자를 만족하는 모든 요소들을 배열에 인덱스에 맞는 요소를 반환합니다.
document.querySelectorAll("선택자명")[인덱스]
// 새로운 노드를 생성합니다.
const div = document.createElement('div');
document.body.append(div);
document.body.append(div);
// Changing
// 이 둘은 차이가 있어요!
element.innerHTML = new html content
element.innerText = new text
// style을 바꿔요.
element.style.property = new style
//method를 통해 클래스를 추가해봐요.
element.setAttribute(attribute, value)
// 어랏? 그럼 이런것도 가능
element.setAttribute("style", "background-color:red;");
element.style.backgroundColor = "red";
클래스
클래스
- 값처럼 사용할 수 있는 일급 객체
- 특징
✔︎ 무명의 리터럴로 생성할 수 있다. 즉, 런타임에 생성이 가능하다
✔︎ 변수나 자료구조(객체, 배열 등)에 저장할 수 있다.
✔︎ 함수의 매개변수에게 전달할 수 있다.
✔︎ 함수의 반환값으로 사용할 수 있다. - 클래스 몸체에서 정의할 수 있는 메서드는 constructor(생성자), 프로토타입 메서드, 정적 메서드의 세 가지가 있다.
- 클래스는 생성자 함수와 유사하게 동작하지만 몇 가지 차이가 있다
- 클래스를 new 연산자 없이 호출하면 에러가 발생한다.
하지만 생성자 함수를 new 연산자 없이 호출하면 일반 함수로서 호출된다. - 클래스는 상속을 지원하는 extends와 super 키워드를 제공한다.
하지만 생성자 함수는 extends와 super 키워드를 지원하지 않는다. - 클래스는 호이스팅이 발생하지 않는 것처럼 동작한다.
하지만 함수 선언문으로 정의된 생성자 함수는 함수 호이스팅이, 함수 표현식으로 정의한 생성자 함수는 변수 호이스팅이 발생한다. - 클래스 내의 모든 코드에는 암묵적으로 strict mode가 지정되어 실행되며 strict mode를 해제할 수 없다.
하지만 생성자 함수는 암묵적으로 strict mode가 지정되지 않는다. - 클래스의 constructor, 프로토타입 메서드, 정적 메서드는 모두 프로퍼티 어트리뷰트 [[Enumrable]]의 값이 false다.
다시 말해, 열거되지 않는다.
- 클래스를 new 연산자 없이 호출하면 에러가 발생한다.
- 인스턴스
//클래스 선언문
class Person{
//생성자
constructor(name){
this.name = name; // name 프로퍼티는 public하다
}
//프로토타입 메서드
sayHi(){
console.log(`Hi! My name is ${this.name}`);
}
//정적 메서드
static sayHello(){
console.log('Hello!');
}
}
//인스턴스 생성
const me = new Person('Lee');
//인스턴스의 프로퍼티 참조
console.log(me.name); // Lee
//프로토타입 메서드 호출
me.sayHi(); // Hi! My name is Lee
//정적 메서드 호출
Person.sayHello(); // Hello!
인스턴스 생성
- 클래스는 생성자 함수이며 new 연산자와 함께 호출되어 인스턴스를 생성
class Person {}
const me = new Person();
console.log(me); // Person {}
- 함수는 new 연산자의 사용 여부에 따라 일반 함수로 호출되거나
인스턴스 생성을 위한 생성자 함수로 호출되지만
클래스는 인스턴스를 생성하는 것이 유일한 존재 이유이므로 반드시 new 연산자와 함께 호출
-> 클래스를 new 연산자 없이 호출하면 타입 에러 발생 - 클래스 표현식으로 정의된 클래스의 경우,
클래스를 가리키는 식별자(Person)를 사용해 인스턴스를 생성하지 않고 기명 클래스 표현식의 클래스 이름(MyClass)을 사용해 인스턴스를 생성하면 에러가 발생
const Person = class MyClass {};
const me = new Person();
console.log(MyClass); // ReferenceError
const you = new MyClass(); // ReferenceError
- 기명 함수 표현식과 마찬가지로 클래스 표현식에서 사용한 클래스 이름은 외부 코드에서 접근 불가능
생성자 함수
- return 값을 만들지 않는다
- 인스턴스가 만들어질 때 실행되는 코드
- 생성자 함수의 함수 몸체에서 수행해야 하는 것
✔︎ 인스턴스를 생성
✔︎ 생성된 인스턴스를 초기화(인스턴스 프로퍼티 추가 및 초기값 할당)
ES5 클래스 작성 문법
- 클래스를 작성하는데 function 키워드를 사용
- 클래스 이름은 함수 이름 규칙을 따른다
- 일반적으로 클래스 이름의 첫 글자는 대문자
function MyClass() {
// constructor(생성자) 함수
}
MyClass.prototype.methodName = function() {
// 메서드 내용
}
- 위와 같이 클래스 생성자를 정의하고, prototype 객체에 메서드를 추가
- 이후 해당 클래스의 인스턴스를 생성할 때 new 키워드를 사용
let myInstance = new MyClass();
//ES5 작성 예시
function Car(brand, name, color) {
this.brand = brand;
this.name = name;
this.color = color;
}
Car.prototype.drive = function() {
console.log(this.name + '가 운전을 시작합니다.');
}
let avante = new Car('hyundai', 'avante', 'black');
avante.color; // black
avante.drive(); // 'avante'가 운전을 시작합니다.'
ES6 클래스 작성 문법
//ES5 예제를 ES6로 만들어보기
class Car {
constructor(brand, name, color) {
this.brand = brand;
this.name = name;
this.color = color;
}
drive() {
console.log(${this.name}가 운전을 시작합니다.);
}
}
let avante = new Car('hyundai', 'avante', 'black');
avante.color; // black
avante.drive(); // 'avante'가 운전을 시작합니다.'
Getter, Setter
- class에서는 getter와 setter를 사용하여 class 속성에 접근할 수 있다.
- getter : 속성 값을 반환하는 메소드
- setter : 속성 값을 설정하는 메소드
class Rectangle {
constructor(height, width) {
// underscore : private, _ 안 쓰면 에러남
this._height = height;
this._width = width;
}
get width() {
return this._width;
}
//외부에서 들어왔을 때 내부에서 검증하고 세팅할 수 있음
set width(value) {
if (value <= 0) {
console.log("[오류] 가로길이는 0보다 커야 합니다");
return;
} else if (typeof value !== "number") {
console.log("[오류] 세로길이로 입력된 값이 숫자타입이 아닙니다!");
return;
}
this._width = value;
}
get height() {
return this._height;
}
set height(value) {
if (value <= 0) {
console.log("[오류] 세로길이는 0보다 커야 합니다");
return;
} else if (typeof value !== "number") {
console.log("[오류] 세로길이로 입력된 값이 숫자타입이 아닙니다!");
return;
}
this._height = value;
}
getArea() {
const a = this._height * this._width;
console.log(`넓이는 ${a}입니다`);
}
}
const rectangle1 = new Rectangle(10, 20);
rectangle1.getArea(); // 넓이는 200입니다
상속(Inheritance)
- class는 상속을 통해 다른 class의 기능을 물려받을 수 있다
- 상속을 받는 class : subclass / derived class
- 상속을 하는 class : superclass / base class
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} says!`);
}
}
class Dog extends Animal {
// 부모에게서 내려받은 메서드를 재정의할 수 있음
// overriding : 부모에게 내려받아서 재정의 하는 것
speak() {
console.log(`${this.name} barks`);
}
}
const me = new Dog("dd");
me.speak();
클로저
- 클로저는 함수와 그 함수가 선언된 렉시컬 환경과의 조합
- 렉시컬 스코프 : 스코프에 대한 참조는 함수 정의가평가되는 시점에 함수가 정의된 환경(위치)에 의해 결정
- outer : 정의된 환경에 대한 정보를 저장하는 곳
- 외부 함수보다 중첩 함수가 더 오래 유지되는 경우, 중첩 함수는 이미 생명 주기가 종료한 외부 함수의 변수를 여전히 참조할 수 있다.
- 클로저를 사용하는 이유
- 상태를 안전하게 변경하고 유지하기 위해 사용
- 은닉하다(특정 함수에게만 상태 변경을 허용한다)
- 캡슐화 : 프로퍼티와 메서드를 하나로 묶는 것
예시)
// 함수가 호출될 때마다 호출된 횟수를 누적하여 출력하는 카운터를 구현해보자
let num = 0;
const increase = function () {
return ++num;
};
console.log(increase());
// num = 100; // 치명적인 단점이 있어요.
console.log(increase());
console.log(increase());
// 보완점
// num은 increase 함수가 호출되기 전까지변경되지 않고 유지돼야 함
// num은 increase 함수만이 변경할 수 있음
// 전역변수인 num이 문제다 -> 지역변수로 바꿔보자
// 클로저를 활용해 리팩토링
const increase = (function () {
let num = 0;
// 클로저
return function () {
return ++num;
};
})();
// 이전 상태값을 유지
console.log(increase()); //1
console.log(increase()); //2
console.log(increase()); //3
// 기능을 확장해보자
const increase = (function () {
let num = 0;
// 클로저인 메서드 (increase, decrease)를 갖는 객체를 반환
// property는 public -> 은닉되지 않는다.
return {
increase() {
return ++num;
},
decrease() {
return num > 0 ? --num : 0;
},
};
})();
console.log(counter.increase()); // 1
console.log(counter.increase()); // 2
console.log(counter.decrease()); // 1
console.log(counter.decrease()); // 0
'항해 > TIL' 카테고리의 다른 글
TIL(2/15) / 객체, 변경불가성, 빌트인 객체 (0) | 2024.02.15 |
---|---|
TIL(2/13) / JS 메서드 (0) | 2024.02.13 |
TIL(2/8) / JS 4 (콜백함수, 동기/비동기) (0) | 2024.02.08 |
TIL(2/7) / JS 3 (실행 컨텍스트, this) (0) | 2024.02.07 |
TIL(2/6) / JS 2 (일급 객체, Map&Set) (0) | 2024.02.06 |