일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- mock api를 이용한 react 테스트
- 비동기 테스트
- jest
- javascript 테스트
- Testing-library/react
- React Testing Library
- 리액트 테스트
- TDD방식으로 리액트 테스팅
- CSS
- react
- react 테스트
- nest.js circular Dependency
- TodoList 테스트 코드
- 첫코딩
- 리액트 테스트 코드
- FlatList 무한 스크롤
- react testing library 비동기 테스트 사용법
- JavaScript
- react native 무한스크롤
- nest.js 순환 참조
- react jest
- 개발
- 첫 코딩
- ScrollView 무한 스크롤
- React 테스트코드
- 프로젝트 배포하기
- nest.js 순환 종속성
- mock api 사용법
- nest.js forwardRef
- HTML
- Today
- Total
성장을 위한 기록
중급 기본 정리 (with 앙마코딩) Class 클래스 본문
이 글은 인프런에서 앙마코딩님의 무료 강좌를 학습한 내용입니다. (자바스크립트 중급 강좌)
문제 시 바로 삭제하겠습니다.
출처 [무료] 자바스크립트 중급 강좌 대시보드 - 인프런 | 강의 (inflearn.com)
Class
클래스는 ES6 이후에 추가됐고 생성자 함수를 만들 수 있다.
const User = function (name,age){
this.name = name;
this.age = age;
this.showName = function (){
console.log(this.name);
};
};
const btae = new User('Btae',27);
class User2 {
constructor(name,age){
this.name = name;
this.age = age;
}
showName(){
cosole.log(this.name)
}
}
const tom = new User2('Tom',30);
User와 User2 듈다 객체를 만들 수 있는데 약간의 차이가 있다.
우선 구조를 살펴봤을 때Class
에서 constructor
부분은 객체를 만든다는 의미로 사용되며 인수를 받을 수 있다.
또한 생성자 함수에는 showName
함수가 같이 선언했지만, Class에서는 객체 밖에 선언을 한다.btae > User {name:'Btae', age: 27, showName:f}
(여기서 f는 함수라는 의미)tom > User2 {name:'Tom', age:30 }
콘솔창에서 확인해보면 User2에는 함수가 없다. 그 이유는 prototype에 저장되기 때문이다.
따라서 __proto__
를 눌러보면 그 안에 showName()이 존재한다.
그렇다고해서 사용이 불가능 한 것은 아니고 똑같이 (btae or tom).showName();
을 사용할 수 있다.
쉽게 설명하자면
위 예제에 User 생성자 함수를 아래 예제처럼 변경하면 User2와 똑같은 모습을 갖출 수 있다.
const User = function (name,age){
this.name = name;
this.age = age;
};
User.prototpye.showName = function() {
console.log(this.name);
};
const btae = new User('Btae',27);
User2와 동일하게 하기 위해 객체를 생성한 뒤 함수는 prototype을 통해 상속받았다. (똑같이 __proto__ 내부에 들어가게 된다.)
세부적인 기능 차이는?
단순히 구성을 깔끔하게 하기 위해서만 Class를 사용할까?
당연히 아니다. (그렇게만 사용할 꺼면 이걸 만들 이유가?....)
여러 이유가 있지만, new를 안붙였을 때 Error가 뜨는지, 없이 동작하는지에 대한 차이가 있다.
앞선 예제를 조금만 변형해서 가져와 보겠다.
const User = function (name,age){
this.name = name;
this.age = age;
};
User.prototpye.showName = function() {
console.log(this.name);
};
const btae = User('Btae',27);
class User2 {
constructor(name,age){
this.name = name;
this.age = age;
}
showName(){
cosole.log(this.name)
}
}
const tom = User2('Tom',30);
차이가 있다면 생성자 함수를 변수에 할당할 때 new값을 빼먹었다. 즉 실수가 발생했다.
이때 두 변수를 콘솔로 입력해보면
btae > undefined
tom > Error .....
생성자 함수에 경우 new를 뺏을 때 위 예제이는 함수에 반환(return)값이 없기 때문에 undefined가 할당되고 에러는 발생하지 않는다.
반대로 Class로 작성했을 경우 변수에 할당할 때 new가 필요하다는 error가 발생한다.
이러한 차이로 코딩 중 실수가 생겼을 때 Class는 즉각적으로 알아 챌 수 있다.
또 다른 차이점은 for in 문에서 나타난다.
다시 new를 붙여 작성했다고 가정하고 예제를 들어보면
for(const p in btae){
console.log(p);
}
/* name
age
showName
*/
----------------------
for(const p in tom){
console.log(p);
}
/*
namme
age
*/
tom과 btae의 구성은 동일하다. for in 문의 반환값이 다르다.
for in 문은 __proto__
에 있는 프로퍼티도 반환하게 된다. 그래서 우리는 객체 내에만 존재하는 프로퍼티를 반환하기 위해 hasOwnProperty
를 사용했다.
다만 Class를 사용할 경우 hasOwnProperty
를 사용하지 않고 객체 내에만 존재하는 프로퍼티를 반환 할 수 있다.
Class 생성자 상속하기
기존 생성자 함수의 .prototype / __proto__ 와 달리 extends를 사용한다.
class Car {
constructor(color){
this.color = color;
this.wheels = 4;
}
drive(){
console.log('drive');
}
stop() {
console.log('stop!');
}
}
class Kia extends Car { //Car를 Kia에 상속하기 extends 사용
park() {
console.log('park');
}
}
const k5 = new Kia('red');
사진처럼 상속이 잘됐다. 자세히 들여다 보면 Kia 객체에 상속 Car이 있고 Car안에 있던 함수는 prototype 안에 있다.
따라서 객체에서 찾게 되면 Kia를 시작으로 Car 그리고 Car prototype 순으로 진행된다.
그렇다면 Car 안에 있는 프로퍼티를 Kia에서 중복사용하게 되면 어떻게 될까?
값을 찾을 때 처음 값만 찾고 중단된다는 것만 알고 있으면 당연하게도 덮어쓰여진다는 걸 알 수 있다.
만약 같은 프로퍼티라도 사용하고 싶으면 super
을 사용하면 된다.
class Car {
constructor(color){
this.color = color;
this.wheels = 4;
}
drive(){
console.log('drive');
}
stop() {
console.log('stop!');
}
}
class Kia extends Car { //Car를 Kia에 상속하기 extends 사용
park() {
console.log('park');
}
stop() {
super.stop(); // 이게 없다면 stop();은 덮어 써진다.
console.log('NO');
}
}
const k5 = new Kia('red');
위 예제처럼 super.stop()을 사용하여 부모 클래스 즉 상속받은 메서드를 사용 할 수 있다.
이를 오버라이딩(overriding) 이라 한다.
자식 class에서 constructor 사용하기
위 예제에는 자식 class에 함수만 있었지만 constructor을 이용하여 프로퍼티를 추가할 수 있다.
단, 몇가지 주위할 점이 있다.
우선 완성된 예저를 보자 (앞부분은 생략)
.......
class Kia extends Car {
constructor(color){ //color 인수 (설명.1)
super(color); // super 사용 (설명.2)
this.navigation = 1;
}
park() {
console.log('park');
}
}
const k5 = new Kia('red');
위 예제에서 2번 super을 사용하지 않으면 error가 난다.
이유는 class를 선언할 때 보이지는 않지만 constructor에 빈 객체({})를 생성한 후 this.를 통해 프로퍼티와 값을 받는다.
하지만 상속받는 과정 (extends를 사용)에서는 constructor가 있지만 빈 객체를 생성하지 않기 때문에 다음에 오는 프로퍼티를 받을 수 없다.
따라서 상위 class 즉 상속받은 부모 class에 있는 constructor를 사용하기 위해서 super();
을 추가해야한다.
1,2 번에서 인수 color가 들어갔다. 만약 color가 없다면? 동작은 잘 되지만 k5.color 값은 undefined가 된다.
그 이유는 const k5 = new Kia('red');
에서 입력한 red라는 인수가 color프로퍼티를 가지고 있는 부모 class까지 전달되지 않기 때문이다.
인수를 전달하기 위해서는 자신의 class에 있는 constructor에도 똑같이 인수를 전달 받을 수 있는 구조를 만들어야하기 때문에 1,2번처럼 color를 작성해야 한다.
이 과정을 작동 순서로 나타내보면, 전달받은 인수는 처음에 Kia의 constructor로 전달받고 super(color)를 통해 부모 class에서 color에 전달하는 것이다.
여기서 드는 의문?
Kia에서 contructor를 작성하기 전 예제에서는 ( constructor로 묶이는 부분이 없을 때) Kia.color >> 'red'로 잘 나타났다.
그런데 constructor를 작성한 후에는 인수를 전달하지 않으면 작동이 되지 않는다.
바로 작성하지 않았을 때 보이지 않은 constructor가 있기 때문이다. (있다고 생각하는게 맞을지는 모르지만)
class Kia extends Car {
/*constructor(...arr){
super(...arr);
}*/
park() {
console.log('park');
}
}
const k5 = new Kia('red');
js에서 실행할 때 주석처리된 부분이 있다고 생각하고 처리하게 된다. 따라서 자동으로 인수를 전달 할 수 있다.
하지만 직접 constructor을 작성하게 되면 주석 부분은 사라지고 작성된 constructor을 따라 작동하게 된다.
'FE (Front End) (구) > javascript' 카테고리의 다른 글
중급 기본 정리 (with 앙마코딩) promise 2탄 async, await (0) | 2022.03.20 |
---|---|
중급 기본 정리 (with 앙마코딩) Promise 프로미스 async, await (0) | 2022.03.19 |
중급 기본 정리 (with 앙마코딩) 상속과 Prototype (0) | 2022.03.17 |
중급 기본 정리 (with 앙마코딩) call, apply, bind (0) | 2022.03.16 |
중급 기본 정리 (with 앙마코딩) setTimeout / setInterval (0) | 2022.03.16 |