클래스는 ES6 부터 제공되는 기능이다. 클래스는 객체가 아니고 객체를 담는 template 라고 생각하면 된다.(근데 typeof 클래스 라고 하면 fucntion이 나온다.) 참고로 클래스의 첫번째 method이름은 반드시 'constructor' 이어야 한다. 'constructor'를 통해 만들어진 property가 뒤에 사용된다. 마찬가지로 new를 통해 생성자 함수로 만들고 그 뒤에 계속 복제 가능하다. 비유를 하자면 붕어빵 찍는 틀이 class이고 틀로 인해 만들어진 붕어빵이 object(instnace of class)가 된다. 사실 클래스는 기존에 자바스크립트에서 존재하던 function에 또 다른 기능을 추가한것이다. 이렇게 원형이 존재하고 그 원형에 몇가지 기능을 추가해서 문법을 새로 만드는 것을 syntatical suger
라고도 한다. 그럼 예시로 배워보자.
class Car {
constructor(name, year) {
// constructor method
this.name = name; //property. 어떻게 보면 클래스 안에서 변수를 설정한다고 보면 될 것 같다.
this.year = year;
}
age() {
let date = new Date();
return date.getFullYear() - this.year;
}
thirdMethod() {
return;
}
}
let myCar = new Car("Ford", 2014); // 클래스를 사용하기 전에 선언해주자.
console.log(myCar);
// name : Ford
// year : 2014
console.log(myCar.age());
// 7
클래스를 사용할 때 는 변수처럼 선언해야한다. 그리고 클래스는 호이스팅이 되지 않는다.(여기서 말하는 호이스팅이란 선언하는 순간 선언된 대상이 유효범위(스코프)의 최상단까지 '끌어올려져서'(hoisted) 선언되는 것을 의미한다. 함수안에서 호이스팅되면 함수 최상단에, 그게 아니면 전역 최상단에 선언되어서 '어느 줄에서나 사용가능한 상태'를 의미한다.)
이처럼 호이스팅 되지 않는것은 선언하고 나서 사용가능하다.
또한 그 전에 글에서 함수를 객체로 만든다음 메소드를 추가할때는 prototype을 통해서 메소드를 따로 빼서 추가한다음 공유하게 했다. 클래스에선 그럴필요 없다. 클래스 안에 메소드를 추가하면 자동으로 공유가능하게 따로 빼논것 처럼 되어버린다.
P.S: 참고로 var,let,const는 hoisting 된다. 다만 let,const는 선언하고나서 할당하기 전에 사용하면 cannot access before initialization
이라고 뜬다.(여기서 initialization은 선언과 할당이 모두 이루어진 상태를 의미한다. 에러 없이 완벽하게 사용가능한 상태를 말한다) 일단 hositing 되긴 되었는데 할당이 안되었다는 뜻이다. 그래서 hoisiting이 일단은 된다는 것을 알 수 있다.
var 같은 경우는 선언만 할경우 hoisting 되면서 default 로 undefined
가 할당된다.
그리고 function은 hositing도 되면서 동시에 initialized도 되기 때문에 reference 에러나 TDZ 에러도 발생하지 않고 사용가능하다.
그리고 선언은 과 할당사이 또는 선언 전의 공간을 Temporal Dead Zone(TDZ)
라고 한다. 변수가 사용불가능한 영역인것이다.
// TDZ
// TDZ
// TDZ
console.log(greeting); // cannot access 'greeting' before initialization
// TDZ
// TDZ
let greeting;
// TDZ
// TDZ
greeting = "Hello"; // TDZ for 'let greeting' ends here
파이썬에서 처럼 인자형태로 PASS 되서 확장되는게 아니라 extends
라는 키워드로 확장된다. 또한 부모 클래스의 method를 사용하고 싶을때 super() 함수를 사용한다. sass css 의 extend랑 거의 같은 개념이라고 봐도 된다. super가 없다면 부모 클래스의 코드를 자식 클래스안에서 다시 작성해줘야한다. 그럼 상속의 의미가 없어짐. super를 사용해서 부모클래스의 속성을 가져다 쓰고 추가적인 부분은 자식 클래스에 작성한다.
class Person {
constructor(name, first, second) {
this.name = name;
this.first = first;
this.second = second;
}
sum() {
return this.first + this.second;
}
}
class PersonPlus extends Person {
//Person 클래스를 Personplus에 확장시켰다
constructor(name, first, second, third) {
// super()는 생성자 클래스를 의미
super(name, first, second);
this.third = third;
}
sum() {
//super.property ==> 부모클래스의 property를 불러올때 점을 찍는다
return super.sum() + this.third;
}
avg() {
return (this.first + this.second) / 2;
}
}
var kim = new PersonPlus("kim", 10, 20, 30);
console.log("kim.sum()", kim.sum());
console.log("kim.avg()", kim.avg());
// kim.sum() 60
// kim.avg() 15
클래스가 아닌 일반 객체끼리도 상속기능을 쓸 수 있다. 자바스크립트만이 가진 특징이라고도 할 수 있다(보통 클래스끼리 상속하기 때문) __proto__
라는 키워드를 사용하는 것이다.(다만 이 방법은 비표준화된 방법이다)
var superObj = { superVal: "super" };
var subObj = { subVal: "sub" };
//subObj에 superObj를 상속하자
subObj.__proto__ = superObj;
console.log("subObj.subVal =>", subObj.subVal);
console.log("subObj.superVal =>", subObj.superVal);
// subObj.subVal => sub
// subObj.superVal => super
// 만약 superObj에서 상속받은 속성을 subObj에서 변경하면 superObj 도 바뀔까?
subObj.superVal = "sub";
console.log("superObj.superVal =>", superObj.superVal);
// superObj.superVal => super
// 아니다 subObj의 proto 만 바뀔뿐 부모 객체의 속성은 바뀌지 않는다.
그러나 proto를 써서 바꿀 수 도 있지만 이름도 헷갈리기 때문에 더 괜찮은 방법으로 상속하는 방법이 있다. 바로 object.create() 메소드를 사용하는거다.(표준화된 방법이다)
var superObj = { superVal: "super" };
//superObj를 prototype으로 하는 객체를 subObj 에 상속함. 그리고 새로운 객체(subOjb)를 만들어 냄
var subObj = Object.create(superObj);
// subVal property를 지정하자.
subObj.subVal = "sub";
// proto와의 차이점은 상속한 부모 객체의 속성을 바꿀 수 있다는 것이다.
subObj.superVal = "changedSuperVal";
console.log("subObj.subVal =>", subObj.subVal);
console.log("subObj.superVal =>", subObj.superVal);
// subObj.subVal => sub
// subObj.superVal => changedSuperVal
console.log("superObj.superVal =>", superObj.superVal);
// superObj.superVal => super
debugger;
그리고 debugger
라는 키워드가 있는데 실행시키면 웹을 잠시 멈추고 코드와 코드의 속성을 볼 수 있다.
watch에서 subObj를 검색하면 proto링크가 superObj로 향한다는 것을 알 수 있다.
{:class="img-fluid"}