오늘은 이러한 자바스크립트 심화 개념들을 공부했다.
- 함수와 객체
- 생성자 함수
- 클래스와 상속
- 접근자 프로퍼티와 은닉
- property attribute
- spread
- distructuring
✅ 1. 함수와 객체
자바스크립트에서 함수는 그 자체로 ‘값’처럼 다뤄진다. 그래서 함수를 변수에 넣고, 다른 함수에 넘기고, 심지어 함수에서 함수로 리턴하는 것도 가능하다. 이걸 일급 객체라고 한다.
const sayHi = function() { console.log("Hi"); };
function run(callback) { callback(); }
run(sayHi); // 가능
또 하나 중요한 건 arguments 객체다. 함수에 몇 개의 인자가 들어오든 arguments로 다 꺼내 쓸 수 있어서 유연한 함수 구현이 가능하다.
✅ 2. 생성자 함수
같은 속성과 메서드를 가진 객체들을 여러 개 만들어야 할 땐, 생성자 함수를 쓰면 훨씬 효율적이다.
function Animal(type, sound) {
this.type = type;
this.sound = sound;
}
Animal.prototype.speak = function() {
console.log(`${this.sound}!`);
};
const dog = new Animal('강아지', '멍멍');
dog.speak(); // 멍멍!
메서드를 prototype에 정의하면 메모리를 아끼면서 모든 인스턴스가 공유할 수 있다.
✅ 3. 클래스와 상속
ES6부터 class 문법이 도입되면서 훨씬 직관적으로 객체지향 코드를 짤 수 있게 됐다. extends와 super()로 상속도 지원한다.
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name}가 소리를 낸다.`);
}
}
class Dog extends Animal {
speak() {
console.log(`${this.name}가 멍멍 짖는다.`);
}
}
상속받은 자식 클래스는 부모의 메서드를 오버라이딩(재정의) 할 수 있다.오버라이딩과 오버로딩의 개념도 구분해서 정리해 볼 것이다.
✅ 4. 접근자 프로퍼티와 은닉
자바스크립트에서도 getter, setter를 통해 내부 속성 접근을 제어할 수 있다. 특히 #을 붙이면 완전한 은닉(private field) 도 가능하다.
class User {
#name;
constructor(name) {
this.#name = name;
}
get name() { return this.#name; }
set name(newName) { this.#name = newName; }
}
✅ 5. 프로퍼티 어트리뷰트
모든 객체의 프로퍼티는 단순히 값만 있는 게 아니라, writable, enumerable, configurable 같은 속성도 함께 존재한다.
Object.defineProperty(obj, 'name', {
value: '현지',
writable: false,
enumerable: true,
configurable: false
});
이걸 활용하면 특정 속성은 읽기 전용으로 만들거나, for...in에서 숨기기도 가능하다.
✅ 6. 스프레드 문법 (...)
스프레드는 진짜 실무에서 자주 쓰이는 문법이다. 배열, 객체, 함수 인자에 모두 사용 가능하다.
const arr1 = [1, 2];
const arr2 = [...arr1, 3]; // [1, 2, 3]
const obj1 = { a: 1 };
const obj2 = { ...obj1, b: 2 }; // { a:1, b:2 }
기존 값을 유지하면서 확장하는데 매우 유용하다.
✅ 7. 디스트럭쳐링 (구조 분해 할당)
배열이나 객체의 값을 변수로 간편하게 꺼내는 문법이다.
const [a, b] = [1, 2];
const { name, age } = { name: "현지", age: 24 };
또 강사님이 재귀함수 활용 코테 문제를 올려주셔서 한번 풀어봤다.
사실 코테를 많이 풀어보지 못해서 쉬운 문제도 꽤 헤맸다...
[문제 분석] 콜라 문제
빈 병 a개를 주면 콜라 b병을 주는 마트가 있다.
초기 보유한 병이 n개일 때, 받을 수 있는 총 콜라 병 수를 계산하는 문제다.
❌ 내가 처음 작성한 잘못된 코드
function solution(a, b, n) {
let answer = 0;
while (n >= a) {
answer += Math.floor(n / a); //받은 콜라 수가 아니라, 단순한 교환 횟수만 누적
n = Math.floor(n / a) + (n % a);
}
return answer;
}
⚠️ 문제 원인
✅ 고친 코드
function solution(a, b, n) {
let answer = 0;
while (n >= a) {
const exchanged = Math.floor(n / a) * b; // 실제 받은 콜라 병 수
answer += exchanged;
n = exchanged + (n % a); // 다음 단계에서 사용할 병 수
}
return answer;
}
근데 이 문제는 재귀로 풀어야 하는 문제였어서 재귀로 바꿔서도 풀어봤다.
그치만 또 오류가 났다..
❌ 잘못된 재귀 버전 코드
function solution(a, b, n) {
let answer = 0;
if (n < a) return Math.floor(n / a); // 종료 조건도 잘못됨
n = Math.floor(n / a) + (n % a);
answer += solution(a, b, n);
return answer; // 교환한 콜라 수를 반환하지 않음
}
⚠️ 문제 원인 분석
✅ 올바른 재귀 버전 코드
function solution(a, b, n) {
if (n < a) return 0;
const exchanged = Math.floor(n / a) * b;
const remaining = (n % a) + exchanged;
return exchanged + solution(a, b, remaining);
}
-> 종료 조건을 n<a일때 교환 불가능 하기 때문에 이렇게 주고
이번에 받을 콜라 수 : Math.floor(n/a)*b로 횟수만큼 b를 곱해주고
재귀호출로 현재 받은 콜라 수와 다음 단계의 결과를 얻어서 콜라 빈 병의 누적합을 return하게 만들었다
[오버로딩과 오버라이딩]
프론트엔드나 백엔드에서 자바를 다루다 보면 오버라이딩과 오버로딩의 개념이 자주 혼동된다
두 개념이 비슷해 보이지만 전혀 다른 특성을 가지고 있고 어떻게 동작하는지 이해하고 있어야한다고 생각한다.
오버라이딩
class SuwonMember {
String test() {
return "저는 서울에 거주중입니다.";
}
}
class SuwonStudent extends SuwonMember{
String test() {
return "저는 hyunji 입니다.";
}
}
public class OverridingTest {
public static void main(String[] args) {
SuwonStudent student = new SuwonStudent();
System.out.println(student.test());
}
}
결과 : 저는 hyunji입니다.
SuwonMember에서 정의한 test() 메서드의 값 -> '저는 서울에 거주중입니다'가 아닌
SuwonStudent에서 재정의한 값 -> '저는 현 입니다.' 가 출력되는 것을 확인할 수 있다.
이렇게 부모 클래스나 생성자 함수가 가지고 있는 메서드를, 자식 클래스 또는 객체에서 같은 이름으로 재정의하는 것을 오버라이딩이라고 한다.
특징
- 오버라이드 하고자 하는 메소드가 상위 클래스에 존재해야 한다.
- 메소드 이름이 같아야 한다.
- 메소드 파라미터 개수, 파라미터의 자료형이 같아야 한다.
- 메소드 리턴형이 같아야 한다.
- 상위 메소드와 동일하거나 내용이 추가되어야 한다.
오버라이딩시 주의할 점
1. 자식 클래스에서 오버라이딩하는 메소드의 접근 제어자는 부모 클래스보다 더 좁게 설정할 수 없다.
2. Exception은 부모 클래스의 메소드보다 많이 선언할 수 없다.
3. Static 메소드를 인스턴스의 메소드로 또는 그 반대로 바꿀 수 없다.
오버로딩
예를 보면,
class OverloadingMethods {
public void print() {
System.out.println("매개변수X - 오버로딩1");
}
String print(Integer a) {
System.out.println("Integer - 오버로딩2");
return a.toString();
}
void print(String a) {
System.out.println("String - 오버로딩3");
System.out.println(a);
}
String print(Integer a, Integer b) {
System.out.println("Integer, Integer - 오버로딩4");
return a.toString() + b.toString();
}
}
class OverloadingTest {
public static void main(String[] args) {
OverloadingMethods om = new OverloadingMethods();
om.print();
System.out.println(om.print(3));
om.print("Hello!");
System.out.println(om.print(4, 5));
}
}
결과 :
매개변수x - 오버로딩1
Integer - 오버로딩2
3
String - 오버로딩3
Hello!
Integer, Integer - 오버로딩4
45
이렇게 함수 이름은 같지만, 매개변수의 타입이나 개수가 다른 여러 함수를 정의하여 상황에 맞게 호출하는 방식을 오버로딩이라고 한다.
특징
- 메소드 이름이 같아야 한다.
- return형이 같아도 되고 달라도 된다.
- 파라미터 개수가 달라야 한다.
- 파라미터 개수가 같을 경우, 데이터타입이 달라야 한다.
오버로딩을 사용하는 이유는?
- 같은 기능을 하는 메소드를 하나의 이름으로 사용 가능하다.
- 메소드의 이름을 절약할 수 있다.
이렇게 메소드의 이름을 동일하게 만들어 프로그램의 가독성을 증가시킬 수 있다는 장점이 있다.
본 후기는 [카카오엔터프라이즈x스나이퍼팩토리] 카카오클라우드로 배우는 AIaaS 마스터 클래스 (B-log) 리뷰로 작성 되었습니다.
'카카오클라우드 AIaaS 교육 > 클라우드 어플리케이션 개발' 카테고리의 다른 글
| [스나이퍼팩토리] AIaaS 마스터 클래스 8주차 DAY 35 - react (0) | 2025.05.19 |
|---|---|
| [스나이퍼팩토리] AIaaS 마스터 클래스 8주차 DAY 34 - react (0) | 2025.05.19 |
| [스나이퍼팩토리] AIaaS 마스터 클래스 8주차 DAY33 - react (0) | 2025.05.13 |
| [스나이퍼팩토리] AIaaS 마스터 클래스 8주차 DAY32 - js 심화 (2) (0) | 2025.05.13 |
| [스나이퍼팩토리] AIaaS 마스터 클래스 6주차 DAY2 - html (2) | 2025.04.30 |