자바스크립트를 처음 배울때 책이나 강의에서 객체 지향 프로그래밍이라는 말이 자주 등장한다. 하지만 처음 공부를 시작할 때 변수, 데이터 타입 등은 이해를 해도 객체 지향 프로그래밍이라는 단어는 감이 잘 안왔던 내 경험을 토대로 우선 객체 지향 프로그래밍에 대하여 정리해보자 한다.
JS는 명령형, 함수형, 프로토타입 기반 객체지향 언어이다. 자바스크립트는 원시 값을 제외하고 거의 모든 것이 객체로 이루어져 있다. 객체 지향 프로그래밍이란 여러개의 독립적 단위, 즉 객체의 집합으로 프로그램을 표현하려는 프로그래밍 패러다임이다.
장점 | 설명 |
---|---|
재사용성 | 상속을 통해 프로그래밍시 코드의 재사용을 높일 수 있음 |
생산성 향상 | 잘 설계된 클래스를 만들어 독립적인 객체를 사용함으로써 개발의 생산성 향상 |
유지보수의 우수성 | 캡슐화를 통해 주변 영향이 적어 유지보수가 쉽다 |
단점 | 설명 |
---|---|
개발 속도가 느림 | 객체를 처리하려는 것에 대한 정확한 이해가 필요 |
실행 속도가 느림 | 객체지향언어는 대체로 실행속도가 느리다 |
코딩난이도 상승 | 다중 상속과 같은 이유로 복잡도 상승 |
데이터와 코드의 형태를 외부로부터 알 수 없게 하고, 데이터의 구조와 역할, 기능을 하나의 캡슐 형태로 만드는 방법 (정보 은닉)
다양한 속성 중 프로그램에 필요한 속성만 간추려 표현하는 것
부모 클래스에 정의된 변수 및 메서드를 자식 클래스에서 상속받아 사용하는 것
상속과 연관이 있는 개념으로 한 객체가 다른 여러형태(객체)로 재구성 되는 것
new 연산자와 함께 호출하여 객체(인스턴스)를 생성하는 함수를 말한다. 생성자 함수에 의해 생성된 객체를 인스턴스라 한다.
// 빈 객체의 생성
const person = new Object(); // {}
// 자바스크립트는 Object 생성자 함수 이외에도
//String,Number,Boolean,Function,Array,Date,RegExp,Promise 등의 빌트인 생성자 함수를 제공
const strObj = new String('abc');
const numObj = new Number(123);
const boolObj = new Boolean(true);
const func = new Function('x','return x * x');
const arr = new Array(1,2,3);
const regExp = new RegExp(/ab+c/i);
const date = new Date();
객체 리터럴에 의한 객체 생성 방식은 직관적이고 간편하지만 단 하나의 객체만 생성한다. 따라서 동일한 프로퍼티를 갖는 객체를 여러 개 생성해야 하는 경우 비효율적이다. 생성자 함수에 의한 객체 생성 방식은 마치 객체(인스턴스)를 생성하기 위한 템플릿(클래스)처럼 프로퍼티 구조가 동일한 객체 여러 개를 간편하게 생성할 수 있다.
function Circle(radius){
//생성자 함수 내부의 this는 생성자 함수가 생성할 인스턴스를 가르킨다.
this.radius = radius;
this.getDiameter = function(){
return 2 * this.radius;
}
}
const circle1 = new Circle(5) //반지름이 5인 Circle 객체를 생성
const circle2 = new Circle(10) //반지름이 10인 Circle 객체를 생성
즉 생성자 함수란 new 연산자와 함께 인스턴스를 생성하는 함수이다. new 연산자가 없다면 생성자 함수는 일반 함수로 동작한다.
자바스크립트는 프로토타입 기반 객체지향 프로그래밍 언어이다. 자바스크립트에는
class
라는 개념이 존재하기 않았기 때문에프로토타입
이라는 객체를 활용하여class
처럼 표현하기 위해 사용한다고 볼 수 있다. ES6에서 class문법이 추가되었다. 하지만 생김새만 클래스 구조이고, 엔진 내부적으로는 프로토타입 방식으로 작동된다.
class Person {
height = 180; // 인스턴스 변수
//constructor는 이름을 바꿀 수 없다.
constructor(name,age) {
//this는 생성할 인스턴스를 가르킴
this.name = name;
this.age = age;
}
}
let personal = new Person('park',26);
console.log(personal.name); //park
console.log(personal.age); //26
console.log(personal.height); //180
constructor
는 인스턴스를 생성하고 클래스 필드를 초기화하기 위한 특수 메서드
class Calculator {
add(x,y) {
return x+y;
}
}
let calc = new Calculator();
calc.add(5,6) // 11
class Parent {
// ...
}
class Child extends Parent {
// ...
}
extends
키워드는 클래스를 다른 클래스의 하위 클래스로 만들기 위해 사용
extends
키워드를 통해 child 클래스가 parent 클래스를 상속했다.
위 관계를 '부모 클래스-자식 클래스 관계' 혹은 '슈퍼 클래스(superclass)-서브 클래스(subclass) 관계'라고 한다.
클래스를 상속받을 경우
부모 클래스의 값을 상속받고, 추가적으로 자신만의 값을 사용하고 싶다면
super
키워드를 사용할 수 있다.
class Pet {
constructor(name, age) {
console.log('IN PET CONSTRUCTOR!')
this.name = name;
this.age = age;
}
eat() {
return `${this.name} is eating!`
}
}
class Cat extends Pet {
constructor(name, age, livesLeft = 9) {
console.log('IN CAT CONSTRUCTOR!')
super(name, age)
this.livesLeft = livesLeft;
}
meow() {
return 'MEOWWWW'
}
}
const monty = new Cat('monty',9);
// IN CAT CONSTRUCTOR!
// IN PET CONSTRUCTOR!
console.log(monty); // Cat {name: 'monty', age: 9, livesLeft: 9}
최근들어 프론트엔드 프로젝트의 규모가 커짐에 따라 자바스크립트 코드를 여러 파일과 폴더에 나누어 작성하고 서로가 서로를 효율적으로 불러올 수 있도록 해주는 시스템의 필요성이 높아졌다.
이에 따라 ES6에서 모듈 시스템이 추가되었다.
script
태그에 type="module"
어트리뷰트를 추가해주면, 이 파일은 모듈로서 동작한다.
<script type="module" src="index.mjs"></script>
<!--확장자로는 대게 'mjs'가 사용된다.-->
모듈 내부의 가장 바깥 스코프에서 이름을 선언하더라도, 전역 스코프가 아니라 모듈 스코프에서 선언된다. 모듈 스코프에 선언된 이름은 (export 하지 않는다면)해당 모듈 내부에서만 접근할 수 있다. 따라서 여러 모듈의 가장 바깥쪽에서 같은 이름으로 변수, 함수, 클래스를 선언하더라도 서로 다른 스코프에서 선언되기 때문에 이름의 충돌이 생길 일이 없다.
//index.js
import FOO from 'foo.js';
let FooComponent = Foo();
console.log(FooComponent); // 'Hello module!'
//foo.js
export default function Foo(){
return 'Hello module!'
}
//index.js
import FOO from 'foo.js';
let FooComponent = Foo();
console.log(FooComponent.render()); // 'Hello module!'
//foo.js
export default class Foo(){
render(){
return 'Hello module!'
}
}
모듈은
export
와import
를 사용해 가져오기, 내보내기가 가능하다. (변수, 함수, 클래스)
export
를 통해 여러 모듈에서 재사용이 가능하다.
선언과 동시에 export
를 붙여주면 선언과 export
를 한꺼번에 가능
export const spam = 'eggs';
export function add(x, y) {
return x + y;
}
default export
구문을 통해, 모듈을 대표하는 하나의 값을 지정하고 그 값을 다른 모듈에서 편하게 불러와서 사용이 가능하다.
export
혹은 import
하는 이름의 뒤에 as
를 붙여서, 다른 이름이 대신 사용되게 할 수 있다.
const foo = 'bar';
export { foo as FOO }; // FOO 라는 이름으로 export 된다.
import { Component as Comp } from 'react'; // Comp라는 이름으로 import 된다.
https://poiemaweb.com/js-object-oriented-programming
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Classes
https://radait.tistory.com/4
https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-ES6-Class-%EB%AC%B8%EB%B2%95-%EC%99%84%EB%B2%BD-%EC%A0%95%EB%A6%AC
https://helloworldjavascript.net/pages/293-module.html
안녕하세요, 제로베이스 프론트엔드스쿨 멘토입니다. 작성해주신 글 잘 읽었고, 앞으로의 더 나은 블로깅을 응원하는 마음에서 작은 의견을 남기고 갑니다 :)
감사합니다~!