🚀 초보자를 위한 자바스크립트 배열 고급 메소드 완전 정복!

안녕하세요, 지난번에 배열의 기본 개념을 살펴봤는데요. 오늘은 한 단계 더 나아가 자바스크립트 배열의 고급 메소드들을 알아보겠습니다! 이 메소드들은 처음에는 어려워 보일 수 있지만, 실용적인 예시와 함께라면 금방 이해할 수 있을 거예요! 😊

📚 고급 배열 메소드란?

자바스크립트의 고급 배열 메소드들은 배열을 더 효율적으로 조작하고 가공할 수 있게 도와주는 특별한 함수들입니다. 이 메소드들은 코드를 더 간결하고 읽기 쉽게 만들어 줍니다!

1. 🔍 map() - 배열의 모든 요소 변환하기

map() 메소드는 배열의 모든 요소를 변환하여 새로운 배열을 만듭니다. 마치 공장에서 원재료를 새로운 제품으로 바꾸는 것과 같아요!

const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(num => num * 2);
console.log(doubled); // [2, 4, 6, 8, 10]

// 실생활 예시: 상품 가격에 10% 할인 적용하기
const prices = [1000, 2500, 800, 4500];
const discounted = prices.map(price => price * 0.9);
console.log(discounted); // [900, 2250, 720, 4050]

2. 🧹 filter() - 조건에 맞는 요소만 선택하기

filter() 메소드는 특정 조건을 만족하는 요소만 선택하여 새 배열을 만듭니다. 마치 체를 이용해 원하는 것만 걸러내는 것과 같아요!

const scores = [85, 40, 92, 65, 30, 77];
const passingScores = scores.filter(score => score >= 60);
console.log(passingScores); // [85, 92, 65, 77]

// 실생활 예시: 완료된 할 일만 필터링하기
const todos = [
  {task: '운동하기', completed: true},
  {task: '쇼핑하기', completed: false},
  {task: '책읽기', completed: true}
];
const completedTasks = todos.filter(todo => todo.completed);

3. 💰 reduce() - 배열의 값들을 하나로 합치기

reduce() 메소드는 배열의 모든 요소를 순회하며 하나의 결과값으로 줄여줍니다. 마치 여러 재료를 넣고 하나의 요리를 만드는 것과 같아요!

const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((total, num) => total + num, 0);
console.log(sum); // 15

// 실생활 예시: 장바구니 상품 총액 계산하기
const cart = [{name: '노트북', price: 1200000}, {name: '마우스', price: 35000}];
const totalPrice = cart.reduce((total, item) => total + item.price, 0);

4. 🔎 find() - 조건에 맞는 첫 번째 요소 찾기

find() 메소드는 조건을 만족하는 첫 번째 요소를 반환합니다. 마치 바늘 더미에서 특정 바늘을 찾는 것과 같아요!

const users = [
  {id: 1, name: '철수', age: 25},
  {id: 2, name: '영희', age: 17},
  {id: 3, name: '민수', age: 32}
];
const adult = users.find(user => user.age >= 18);
console.log(adult); // {id: 1, name: '철수', age: 25}

5. ✅ every() & some() - 조건 검사하기

  • every(): 모든 요소가 조건을 만족하는지 확인 (AND 연산)
  • some(): 하나라도 조건을 만족하는지 확인 (OR 연산)
const teamAges = [24, 30, 18, 20, 22];
const allAdults = teamAges.every(age => age >= 18); // true
const anyTeenager = teamAges.some(age => age < 20); // true

6. 🔄 forEach() - 각 요소에 대해 함수 실행하기

forEach() 메소드는 배열의 각 요소에 대해 함수를 실행합니다. map()과 달리 새 배열을 반환하지 않아요!

const fruits = ['🍎', '🍌', '🍊'];
fruits.forEach((fruit, index) => {
  console.log(`${index+1}번째 과일: ${fruit}`);
});
// 출력: "1번째 과일: 🍎" "2번째 과일: 🍌" "3번째 과일: 🍊"

7. 🧩 flatMap() - 매핑 후 평탄화하기

flatMap() 메소드는 map()을 실행한 후 결과를 1단계 평탄화합니다. 중첩된 배열을 다룰 때 유용해요!

const sentences = ['안녕하세요!', '자바스크립트 배열 메소드는 정말 편리해요.'];
const words = sentences.flatMap(sentence => sentence.split(' '));
// ['안녕하세요!', '자바스크립트', '배열', '메소드는', '정말', '편리해요.']

🌟 메소드 체이닝 - 여러 메소드 연결하기

고급 배열 메소드의 진정한 힘은 메소드 체이닝을 통해 발휘됩니다! 여러 메소드를 연결해서 복잡한 작업을 간단하게 처리할 수 있어요!

const products = [
  {name: '노트북', price: 1200000, inStock: true},
  {name: '키보드', price: 45000, inStock: false},
  {name: '마우스', price: 35000, inStock: true},
  {name: '모니터', price: 350000, inStock: true}
];

// 재고 있는 상품만 골라서 가격에 10% 할인 적용 후 총액 계산
const totalDiscounted = products
  .filter(p => p.inStock)
  .map(p => p.price * 0.9)
  .reduce((total, price) => total + price, 0);

🏆 실생활 활용 사례

  1. 📊 데이터 필터링 및 변환
    • 설문 응답 중 특정 조건을 만족하는 데이터만 추출
    • 가격 데이터를 다른 통화로 변환
  2. 📝 통계 계산
    • 배열 요소의 합계, 평균, 최대/최소값 구하기
    • 특정 조건을 만족하는 항목의 개수 세기
  3. 🛒 데이터 정렬 및 그룹화
    • 상품을 가격별로 정렬
    • 사용자를 나이대별로 그룹화

🎁 마무리

이러한 고급 배열 메소드들은 처음에는 복잡해 보일 수 있지만, 익숙해지면 코드를 훨씬 더 효율적으로 작성할 수 있게 해줍니다. 복잡한 반복문을 사용하지 않고도 데이터를 쉽게 처리할 수 있죠! 😄

가장 좋은 학습 방법은 직접 코드를 작성해보는 것입니다. 이 메소드들을 자신의 프로젝트에 적용해보세요! 어떤 메소드가 어떤 상황에서 가장 효과적인지 알게 될 거예요.

다음에는 배열과 관련된 최신 자바스크립트 기능들(구조 분해, 전개 연산자 등)에 대해 알아보겠습니다. 궁금한 점이 있으면 댓글로 남겨주세요! 💬

728x90

⚖️ 동일성 vs 동등성: 차이점은 무엇일까요?

쉽게 설명하자면

  • 동일성(Identity): 두 변수가 정확히 같은 객체를 가리키고 있나요? (참조 비교)
  • 동등성(Equality): 두 객체의 내용이 논리적으로 같은가요? (값 비교)

🔢 자바스크립트의 비교 연산자

자바스크립트에서는 세 가지 비교 방법을 제공합니다

1. == (동등 연산자)

  • 값을 비교하지만, 타입 변환을 수행합니다 (타입이 달라도 값이 같으면 true)
  • 느슨한 비교(loose equality)라고도 합니다

2. === (일치 연산자)

  • 값과 타입 모두 비교합니다 (타입과 값이 모두 같아야 true)
  • 엄격한 비교(strict equality)라고도 합니다

3. Object.is() (ES6에서 도입)

  • ===와 비슷하지만 몇 가지 특수 케이스를 다르게 처리합니다

 

🧩 기본 타입(Primitive) 비교하기

기본 타입(문자열, 숫자, 불리언 등)의 경우 비교가 비교적 직관적입니다

// 문자열 비교
console.log("hello" == "hello");  // true
console.log("hello" === "hello"); // true

// 숫자 비교
console.log(5 == 5);     // true
console.log(5 === 5);    // true
console.log(5 == "5");   // true (타입 변환 발생!)
console.log(5 === "5");  // false (타입이 다름)

 

 

🏠 객체(Object) 비교하기

객체 비교에서 진정한 차이가 드러납니다

// 객체 비교
const apple1 = { weight: 100 };
const apple2 = { weight: 100 };
const apple3 = apple1;

console.log(apple1 == apple2);  // false! 내용은 같지만 다른 객체
console.log(apple1 === apple2); // false! 내용은 같지만 다른 객체
console.log(apple1 == apple3);  // true! 같은 객체를 참조
console.log(apple1 === apple3); // true! 같은 객체를 참조

기억하세요! 자바스크립트에서 객체 비교는 참조(reference)를 비교합니다. 내용이 똑같아도 다른 객체라면 ==와 === 모두 false를 반환합니다! 🤯

 

🧠 객체의 내용 비교하기: 동등성 확인

자바스크립트에는 자바의 equals() 메소드 같은 기본 메소드가 없습니다. 대신, 내용을 비교하려면

방법 1: JSON 변환 (간단하지만 제한적)

const isEqual = (obj1, obj2) => 
  JSON.stringify(obj1) === JSON.stringify(obj2);

console.log(isEqual(apple1, apple2)); // true

이 방법은 간단하지만 함수, 순환 참조, 특수 객체 등을 처리할 수 없습니다.

방법 2: 직접 비교 함수 만들기

function isAppleEqual(apple1, apple2) {
  return apple1 && apple2 && apple1.weight === apple2.weight;
}

console.log(isAppleEqual(apple1, apple2)); // true

방법 3: 라이브러리 사용 (lodash 등)

const _ = require('lodash');
console.log(_.isEqual(apple1, apple2)); // true

 

🧵 문자열: 특별한 경우

자바스크립트에서 문자열 리터럴은 동일한 문자열을 재사용할 수 있지만, new String()으로 생성하면 항상 새 객체가 됩니다:

const str1 = "안녕하세요";
const str2 = "안녕하세요";
const str3 = new String("안녕하세요");

console.log(str1 === str2); // true (같은 문자열 리터럴)
console.log(str1 === str3); // false (객체와 기본 타입)
console.log(str1 === str3.valueOf()); // true (값 비교)

🔢 숫자 래퍼 객체(Number): 자바스크립트 스타일

const num1 = 123;
const num2 = 123;
const num3 = new Number(123);

console.log(num1 === num2); // true (기본 타입 비교)
console.log(num1 === num3); // false (객체와 기본 타입)
console.log(num1 === num3.valueOf()); // true (값 비교)

 

 

🚀 실전 팁: Node.js 백엔드 개발자를 위한 비교 가이드

  1. 기본 타입(Primitive) 비교: === 사용 (타입 안전성)
  2. 객체 참조 비교: === 사용 (동일성 체크)
  3. 객체 내용 비교
    • 간단한 객체: JSON.stringify 또는 커스텀 함수
    • 복잡한 객체: lodash의 _.isEqual 같은 라이브러리
  4. 데이터베이스 ID 비교: 문자열로 변환 후 === 비교
  5.  

🔍 MongoDB ID 비교 예제

Node.js와 MongoDB를 함께 사용할 때 자주 마주치는 상황입니다:

// MongoDB ObjectId 비교 (실제로는 객체)
const id1 = new ObjectId('507f1f77bcf86cd799439011');
const id2 = new ObjectId('507f1f77bcf86cd799439011');

console.log(id1 === id2); // false! 다른 객체
console.log(id1.equals(id2)); // true! MongoDB는 equals() 제공
console.log(id1.toString() === id2.toString()); // true! 문자열 변환

 

🎯 요약: 무엇을 사용해야 할까요?

  1. 기본적으로 === 사용하기 (더 안전하고 예측 가능)
  2. 객체 비교는 내용 비교 함수나 라이브러리 사용하기
  3. ==는 특별한 이유가 있을 때만 사용하기

 

동일성과 동등성에 대해서 설명해주세요.

동일성과 동등성은 객체를 비교할 때 중요한 개념입니다. 자바에서는 이 두 개념을 equals() 메서드와 == 연산자를 통해 구분할 수 있습니다.

equals()와 ==의 차이는 무엇인가요?

equals()는 객체의 내용을 비교하는 반면, ==는 객체의 참조(레퍼런스)를 비교합니다. 따라서 두 객체의 내용이 같더라도 서로 다른 객체라면 equals()는 true를 반환할 수 있지만, ==는 false를 반환합니다.

동등성(Equality)은 뭔가요?

동등성은 논리적으로 객체의 내용이 같은지를 비교하는 개념입니다. 자바에서는 equals() 메서드를 사용하여 객체의 동등성을 비교합니다. Apple 클래스를 예시로 보면, Object.equals 메서드를 오버라이딩하여 객체의 실제 데이터를 비교하도록 했습니다. 그래서 apple과 anotherApple은 다른 객체이지만, 무게가 같기 때문에 동등성 비교 결과 true가 반환됩니다.

public class Apple {

    private final int weight;

    public Apple(int weight) {
        this.weight = weight;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Apple apple = (Apple) o;
        return weight == apple.weight;
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(weight);
    }

    public static void main(String[] args) {
        Apple apple = new Apple(100);
        Apple anotherApple = new Apple(100);

        System.out.println(apple.equals(anotherApple)); // true
    }
}

왜 equals() 메서드를 오버라이딩 했나요?

public class Object {
    ...
    public boolean equals(Object obj) {
        return (this == obj);
    }
    ...
}

Object 클래스의 equals() 메서드는 == 연산자를 사용하여 동일성을 비교합니다. 그리고 모든 클래스는 Object 클래스를 상속하여 동일성 비교를 기본으로 동작하기 때문에, 동등성 비교가 필요한 클래스에서 필요에 맞게 equals & hashCode 메서드를 오버라이딩해야 합니다.

동일성(Identity)은 뭔가요?

동일성은 두 객체가 메모리 상에서 같은 객체인지 비교하는 개념입니다. 자바에서는 == 연산자를 사용하여 객체의 동일성을 비교합니다. == 연산자는 객체의 레퍼런스(참조)를 비교하므로, 두 변수가 동일한 객체를 가리키고 있는지를 확인합니다.

public static void main(String[] args) {
    Apple apple1 = new Apple(100);
    Apple apple2 = new Apple(100);
    Apple apple3 = apple1;

    System.out.println(apple1 == apple2); // false
    System.out.println(apple1 == apple3); // true
}

apple1과 apple2는 참조가 다르기 때문에 == 연산 결과 false가 반환되지만, apple1의 참조를 가지는 apple3은 == 연산 결과 true를 반환합니다.

String은 객체인데 == 비교해도 되던데 어떻게 된건가요?

문자열 리터럴은 문자열 상수 풀(String Constant Pool) 에 저장되기 때문에, 동일한 문자열 리터럴을 참조하면 == 연산자가 true를 반환할 수 있습니다. 하지만 new 키워드를 사용하여 문자열을 생성하면 새로운 객체가 생성되므로 == 연산자가 false를 반환할 수 있습니다. 따라서 문자열 비교 시 항상 equals() 메서드를 사용한 동등성 비교를 하는 것이 좋습니다.

public class StringComparison {
    public static void main(String[] args) {
        String str1 = "안녕하세요";
        String str2 = "안녕하세요";
        String str3 = new String("안녕하세요");
        
        // 동일성 비교
        System.out.println(str1 == str2); // true
        System.out.println(str1 == str3); // false
        
        // 동등성 비교
        System.out.println(str1.equals(str2)); // true
        System.out.println(str1.equals(str3)); // true
    }
}

// String.class equals 오버라이딩 되어있음.
public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    return (anObject instanceof String aString)
            && (!COMPACT_STRINGS || this.coder == aString.coder)
            && StringLatin1.equals(value, aString.value);
}

Integer 같은 래퍼 클래스는 어떻게 비교하나요?

래퍼 클래스도 객체이기 때문에 == 연산자는 참조를 비교합니다. 값 비교를 원할 경우 equals() 메서드를 사용해야 합니다. 다만, 자바는 특정 범위의 래퍼 객체를 캐싱하므로 같은 값의 Integer 객체가 같은 참조를 가질 수 있습니다(-128 ~ 127). 하지만 일반적으로 equals()를 사용하는 것이 안전합니다.

728x90

1. 클로저(Closure)란 무엇인가?

클로저는 JavaScript의 중요한 개념 중 하나로, 함수와 그 함수가 선언된 렉시컬 환경의 조합입니다. 간단히 말해, 클로저는 내부 함수가 외부 함수의 변수에 접근할 수 있게 해주는 기능입니다.

1.1 기본 개념

클로저는 다음과 같은 특징을 가집니다:

  • 함수 내부에 함수를 정의하고 사용
  • 내부 함수가 외부 함수의 변수를 참조
  • 외부 함수가 종료된 후에도 내부 함수가 외부 함수의 변수를 계속 참조 가능

1.2 간단한 예시

function outerFunction(x) {
    let y = 10;
    function innerFunction() {
        console.log(x + y);
    }
    return innerFunction;
}

const closure = outerFunction(5);
closure(); // 출력: 15

이 예시에서 innerFunction은 outerFunction의 변수 x와 y에 접근할 수 있습니다. outerFunction이 실행을 마친 후에도 closure를 통해 innerFunction을 호출하면 여전히 x와 y의 값을 기억하고 있습니다.

 


 

2. 클로저의 장점

2.1 데이터 프라이버시

클로저를 사용하면 private 변수와 유사한 개념을 구현할 수 있습니다. 외부에서 직접 접근할 수 없는 변수를 만들 수 있어 데이터 은닉이 가능합니다.

function createCounter() {
    let count = 0;
    return {
        increment: function() {
            count++;
        },
        getCount: function() {
            return count;
        }
    };
}

const counter = createCounter();
counter.increment();
console.log(counter.getCount()); // 출력: 1
console.log(counter.count); // 출력: undefined

 

2.2 상태 유지

클로저를 사용하면 함수의 상태를 저장하고 유지할 수 있습니다. 이는 함수형 프로그래밍에서 매우 유용합니다.

function createMultiplier(factor) {
    return function(number) {
        return number * factor;
    };
}

const double = createMultiplier(2);
const triple = createMultiplier(3);

console.log(double(5)); // 출력: 10
console.log(triple(5)); // 출력: 15

 


3. 클로저의 단점

3.1 메모리 사용

클로저는 외부 함수의 변수를 계속 참조하기 때문에, 이러한 변수들은 가비지 컬렉션되지 않습니다. 이로 인해 메모리 사용량이 증가할 수 있습니다.

3.2 성능 고려사항

클로저를 과도하게 사용하면 애플리케이션의 성능에 영향을 줄 수 있습니다. 특히 루프 내에서 클로저를 생성할 때 주의가 필요합니다.

function createFunctions() {
    var result = [];
    for (var i = 0; i < 5; i++) {
        result.push(function() { return i; });
    }
    return result;
}

var functions = createFunctions();
for (var i = 0; i < functions.length; i++) {
    console.log(functions[i]()); // 모두 5를 출력
}

이 예시에서 의도와 달리 모든 함수가 5를 반환합니다. 이를 해결하려면 즉시 실행 함수(IIFE)나 let 키워드를 사용해야 합니다.

 


4. 클로저의 실제 활용

4.1 모듈 패턴

클로저를 사용하여 모듈 패턴을 구현할 수 있습니다. 이는 관련 기능을 그룹화하고 네임스페이스를 관리하는 데 유용합니다.

const myModule = (function() {
    let privateVar = 0;

    function privateFunction() {
        console.log('private function');
    }

    return {
        publicVar: 1,
        publicFunction: function() {
            privateVar++;
            privateFunction();
            console.log('public function');
        }
    };
})();

myModule.publicFunction(); // 출력: private function, public function
console.log(myModule.publicVar); // 출력: 1
console.log(myModule.privateVar); // 출력: undefined

4.2 콜백과 이벤트 핸들러

클로저는 비동기 프로그래밍에서 콜백 함수나 이벤트 핸들러를 구현할 때 자주 사용됩니다.

function setupButton(label) {
    let count = 0;
    const button = document.createElement('button');
    button.textContent = label;
    
    button.addEventListener('click', function() {
        count++;
        console.log(`${label} clicked ${count} times`);
    });

    document.body.appendChild(button);
}

setupButton('Click me');

결론

클로저는 JavaScript의 강력하고 유연한 기능 중 하나입니다.

데이터 은닉, 상태 유지, 모듈화 등 다양한 장점을 제공하지만,

메모리 관리와 성능 측면에서 주의가 필요합니다.

 

클로저를 적절히 사용하면 더 깔끔하고 유지보수가 쉬운 코드를 작성할 수 있습니다.

그러나 과도한 사용은 피하고, 필요한 경우에만 신중하게 사용하는 것이 좋습니다.

클로저의 개념을 잘 이해하고 적절히 활용함으로써,

더 효과적이고 강력한 JavaScript 애플리케이션을 개발할 수 있습니다.

728x90

노드JS란?

노드js는 크롬V8 자바스크립트 엔진으로 빌드된 자바스크립트 런타임입니다.

V8엔진은 구글에서 만든 것으로 자바스크립트가 브라우저내에서만 작동가능했던 것을

브라우저 없이도 작동할 수 있도록 만든 것 입니다.

 

쉽게 말하면 노드js란 자바스크립트가 브러우저가 아닌

컴퓨터에서 브라우저 없이 실행하게 도와주는 환경!

 

노드js의 특징: 논 블로킹 I/O , 싱글스레드, 이벤트 루프

논블로킹 I/O : 함수가 실행되는 중에도 다른 작업을 동시에 진행할 수 있는 장점 (비동기 작업을 할때 효율적인 특성)

-> I/O란  입력(Input)/출력(Output)의 약자로, 컴퓨터 및 주변장치에 대하여

               데이터를 전송하는 프로그램, 운영 혹은 장치를 일컫는 말

싱글 스레드 :  스레드 하나를 사용하는 것이며, 동시에 하나의 작업만을 처리할 수 있습니다.

-> 스레드는 프로그램이 동작할 때, CPU 또는 프로세서를 사용하는 단위

이벤트 루프 : JS가 가지고 있는 싱글 스레드의 약점을 극복하기 위해 효율적으로 작업을 처리할 수 있는 특성

 

CMD -> cd C:\Program Files\nodejs 에 들어간 후

node -v 와 node 를 입력해 노드 설치 확인가능

 

REPL이란? 

입력받은 코드를 읽어(Read) 메모리에 저장하고, 평가(Evaluate) 된 값을 출력합니다.

특정 신호를 받기 전까지 위의 과정을 반복(Loop)합니다.

입력하는 코드의 결과를 즉시 확인할 수 있는 개발 환경

(예) CMD, 터미널 또는 F12 검사를 통한 console환경

 

동기(Sync) & 비동기(Async)

 

동기와 비동기에 대한 개념

일반적으로 "동기로 실행된다"라고 함은, 먼저 실행된 코드 결과가 나올때까지 대기 하는 것을 말합니다.

동기 : 놀이기구(전부 내릴때까지 못탐) / 비동기 : 맛집(한명씩 나오면 들어감)

 

블로킹 모델 & 논블로킹 모델

Blocking Model이란, 코드의 실행이 끝나기 전까지 실행 제어권을 다른곳에 넘기지 않아 다른 작업을 하지 못하고 대기

Non-Blocking Model이란, 코드의 실행이 끝나지 않아도 실행 제어권을 다른곳에 넘겨 다음 코드가 실행

결론적으로 자바스크립트는 각 명령들이 순서대로 실행될 수 있게 구현되어 있지만,

                   Non-Blocking Model에 의해 동기적 명령이 아닌 모든 함수는 비동기적으로 실행됩니다.

 

 

프로미스(Promise)

자바스크립트에서 비동기 처리동기로 처리할 수 있게 돕는 Built-in(미리 내부적으로 정의된)객체 유형입니다.

이 객체를 이용하면 여러분은 비동기 처리를 아주 손쉽게 할 수 있습니다.

자바스크립트는 비동기(논블로킹)이지만 Promise 함수를 통해 동기 처리도 가능하다! (예약)

 

Promise 생성자 인터페이스 executor에는 함수만 올 수 있으며 인자로 resolve, reject가 주입됩니다.

executor는 Promise실행 함수라고 불리고, Promise가 만들어질 때 자동으로 실행됩니다.

Promise가 연산을 언제 종료하는지 상관하지 않고, resolve, reject 중 하나를 무조건 호출해야합니다.

new Promise(executor);

// 예제
new Promise((resolve, reject) => {
	// 명령문
});

 

생성자(Constructor)

Javascript에서는 원시 타입(String, Boolean 등) 을 제외한 대부분의 타입들이 객체(Object) 로 구성되어 있습니다.

일반적으로 객체(Object)를 생성하는 함수를 생성자(Constructor) 함수라고 부르게 되는데,

Promise 또한 객체로 구성되어 있기 때문에 생성자 함수를 이용해 Promise를 선언하게 됩니다.

function printFunc(data){
  console.log(data);
}

// 생성자 함수
const obj = new Object();
const promise = new Promise(printFunc);

Promise의 상태

  • 대기(Pending): 이행하거나 거부되지 않은 초기 상태
  • 이행(Fulfilled): 연산이 성공적으로 완료됨
  • 거부(Rejected): 연산이 실패함

Promise가 만들어 질 때 executor가 실행되며, executor에서 resolve 함수가 호출되기 전까지

firstPromise.then(...) 안에 있는 코드를 실행하지 않습니다.

이렇게 executor 가 실행되어 resovle된 프로미스를 Fulfilled Promise라고도 부릅니다.

Promise 안에서 resolve가 실행 된 경우 then 메서드에 작성된 함수가 실행됩니다.

const timerPromise = new Promise((resolve, reject) => { // 이곳에 정의된 함수가 executor
  setTimeout(() => {
	  console.log('First');
		resolve();
	}, 1000);
});

// 이 시점에서 timerPromise는 Fulfilled Promise라고 부를 수 있다.

timerPromise.then(() => {
	console.log('Middle');
	console.log('Last');
});

// Print: First
// Middle
// Last

 

Promise.catch

Promise 안에서 에러가 throw 되거나 reject가 실행되면 catch 메서드에 작성한 함수가 실행됩니다.

const errorPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
	  console.log('First');
		reject('Error!!'); // 직접 reject를 실행하면 프로미스에서 에러가 발생한것으로 간주됩니다.
	}, 1000);
});

errorPromise.then(() => {
	console.log('Middle');
	console.log('Last');
}).catch((error) => {
	console.log('에러 발생!', error);
});

// Print: '에러 발생! Error!!'

 

비동기 함수 (Async Function)

비동기 함수는 일반 함수나 화살표 함수와 아주 비슷하지만 딱 두가지만 다릅니다.

  1. 비동기 함수결과 값항상 Promise 객체로 resolve된다.
  2. 비동기 함수 안에서만 await 연산자를 사용할 수 있다. (바로 아래에서 배웁니다!)

이 두가지 특징을 제외하면 기존처럼 일반 함수나, 화살표 함수처럼 사용할 수 있습니다.

아래처럼요. 아래 세가지 함수 모두 결과 값은 Promise로 받습니다.

 

// 비동기 + 일반 함수
async function 함수이름() {
	// 명령문
}

// 비동기 + 익명 함수
async function() {
  // 명령문
}

// 비동기 + 화살표 함수
async () => {
	// 명령문
}

await 연산자
await 연산자를 사용하면 Promise가 fulfill 상태가 되거나 rejected될 때 까지 함수의 실행을 중단하고 기다릴 수 있습니다.
Promise의 연산이 끝나면 함수에서 반환한 값을 얻을 수 있습니다. (대기한 후 결과값 반환)
await 연산자는 async 함수 안에서만 사용할 수 있습니다

 

const result = await 값;

값에는 Promise가 아닌 다른 값도 들어갈 수 있습니다. 아래처럼!

Promise가 아니라면 기다리지 않고 해당 값 자체를 그대로 반환합니다.

async function 함수이름() {
	const result = await 'Test!';
	console.log(result);
}

함수이름();
// Print: 'Test!';

 

객체 리터럴

객체(Object)란?

Javascript의 데이터 타입은 크게 원시 타입객체 타입으로 분류됩니다.

  • 원시 타입은 단 하나의 값만을 나타내고, 원시 타입의 값은 변경이 불가능 한 값입니다. (true, false)
  • 객체 타입은 다양한 타입의 값을 하나의 단위로 구성한 복합적인 자료 구조이고,
    객체 타입의 값을 변경 가능한 값입니다.

Javascript는 객체(Object) 기반의 프로그래밍 언어이고, Javascript를 구성하는 거의 모든 것은 객체로 구성되어 있습니다. 객체(Object) 는 0개 이상의 프로퍼티로 구성된 집합이며, 하나의 프로퍼티는 KeyValue로 구성되어 있습니다.

 

객체리터럴 이란?

리터럴(literal)은 사람이 이해할 수 있는 문자 또는 약속된 기호를 사용해 값을 생성하는 표기법입니다.

여기서 객체 리터럴은 객체를 생성하기 위한 표기법입니다.

객체 리터럴은 객체를 생성하기 위해 Class를 먼저 선언하고 new 연산자와 함께 생성자를 호출할 필요가 없이 일반적인 숫자, 문자열을 만드는것과 유사하게 객체를 생성할 수 있습니다.

 

객체리터럴로 객체 생성하기

객체 리터럴은 중괄호{} 내에 0개 이상의 프로퍼티를 선언해서 선언합니다.

let objectLiteral = {
    key: 'Value',
    helloWorld: function () {
        return "Hello world";
    }
};

프로퍼티(Property) 란?

객체의 상태를 나타내는 (Data)입니다.

프로퍼티는 (Key)와 (Value)으로 구성되어 있습니다.

const human = {
  // 프로퍼티 키: 'name', 프로퍼티 값: '이용우' 
  name: '이용우',
  // 프로퍼티 키: 'human age', 프로퍼티 값: 28 
  'human age': 28   //' '에서는 띄어쓰기 또는 이미 선언된 이름도 사용가능
}

메서드(Method) 란?

프로퍼티를 참조하고 조작할 수 있는 동작(behavior)을 나타냅니다.

객체의 프로퍼티 값이 함수로 구성되어 있을 경우 메서드(Method)라고 부릅니다.

let objectLiteral = {
    key: 'Value', // 프로퍼티
    helloWorld: function () { // 메서드
        return "Hello world";
    }
};

console.log(objectLiteral.helloWorld()); // Hello world

 

Error handling

- 에러 핸들링(Error handling) 이란?
에러 핸들링은 에러를 관리하는 방법이고, 예상치 못한 상황에 대처하는 방식입니다.
에러는 예상할 수 있는 에러와 예상치 못한 에러로 구분할 수 있는데,

일반적인 어플리케이션을 설계할 때에는 예상치 못한 에러 상황이 더욱 많이 일어날 것으로 가정해야 합니다. 
프로그래머가 작성한 코드에서 예상치 못한 에러가 일어날 가능성은 언제나 존재하고,

이러한 에러 상황을 대비해 언제든지 처리할 수 있어야 합니다.

 

- Try / Catch
서버에서 에러가 발생하지 않게 하기 위해서 저희는 예외 처리를 진행합니다.
예외 처리는 일반적으로 `try … catch` 문을 사용합니다.
`users`에 들어있는 이름들을 `String.toUpperCase()`를 이용하여 대문자로 변경하려할 때

문자열(String)이 아닌 데이터가 들어온다면 에러가 발생합니다.
이렇게 예상치 못한 에러에 대처하기 위해선 `try … catch`문으로 코드 전체를 감쌀 수 있습니다.
에러가 발생하더라도 **프로그램이 멈추지 않고 에러를 기록**할 수 있습니다.

const users = ["Lee", "Kim", "Park", 2];  //2는 문자열이 아니라서 에러

try {
  for (const user of users) {
    console.log(user.toUpperCase());
  }
} catch (err) {
  console.error(`Error: ${err.message}`);
}

// LEE
// KIM
// PARK
// Error: user.toUpperCase is not a function

 

- throw

위에서 에러를 핸들링하는 과정만 공부하였다면, 에러는 무조건 차단하고 발생시키면 안되는 걸까요?

아닙니다. 프로그래머의 입장에서 에러는 고의로 에러를 발생시키기도 해야합니다.

예를 들어서 은행 어플리케이션의 현금 인출 서비스를 만든다고 할 때,

계좌의 잔고가 요청받은 금액보다 적다면 현금 인출을 막고 예외를 발생시켜야겠죠? 이럴때 사용하는 것이 throw입니다.

throw를 호출하면 그 즉시 현재 실행되고 있는 함수는 실행을 멈추게 됩니다.

function withdraw(amount, account) {
  if (amount > account.balance)
    throw new Error("잔고가 부족합니다.");
  account.balance -= amount;
	console.log(`현재 잔고가 ${account.balance}남았습니다.`); // 출력되지 않음
}

const account = { balance: 1000 };
withdraw(2000, account);

// Error: 잔고가 부족합니다.

- finally

try 에서는 HTTP연결이 되고 있거나 파일과 같은 특정한 ‘자원’을 가지고 처리할 때가 있습니다.

하지만 해당 ‘자원'을 계속 가지고 있으면, 무의미한 메모리를 차지하게 될 것 이므로

에러 여부와 상관없이 일정 시점에서는 해당 ‘자원'을 삭제 시켜야합니다.

그렇다면 이 ‘자원'을 삭제하는 시점은 언제가 되어야 할까요?

에러가 언제든지 발생할 수 있는 try? 아니면 에러가 일어났을 때 실행되는 catch?

이런 상황에서는 finally가 필요합니다.

finally는 try/catch 실행후 에러 여부와 상관없이 언제든지 실행됩니다.

function errorException(isThrow) {
  try {
    console.log('자원을 할당하였습니다.');
    if (isThrow) throw new Error();
  } catch (error) {
    console.log('에러가 발생했습니다.');
  } finally {
    console.log('자원을 제거하였습니다.');
  }
}

errorException(false);
// 자원을 할당하였습니다.
// 자원을 제거하였습니다.
errorException(true);
// 자원을 할당하였습니다.
// 에러가 발생했습니다.
// 자원을 제거하였습니다.

 

클래스

- 클래스란?

현실과 비슷한 개념(객체)을 나타내기 위한 도구클래스(Class)라고 부릅니다.

클래스는 미리 정의해놓으면 필요할 때마다 해당 클래스로 동일한 틀을 가진 객체를 만들 수 있습니다.

여기서 동일한 클래스를 이용해 생성한 객체를 인스턴스(Instance)라고 부릅니다

출처 : https://ko.javascript.info/constructor-new

// 클래스, 생성자 함수는 대문자 시작+new를 쓰는 것이 관례
class User { 
}
//user는 인스턴스
const user = new User();
user.name = "이용우";
user.age = 28;
user.tech = "Node.js";

console.log(user.name); // 이용우
console.log(user.age); // 28
console.log(user.tech); // Node.js

생성자(Constructor)

클래스 내부에서 constructor()로 정의한 메서드를 "생성자"라고 부릅니다.

미리 정의한 클래스를 기반으로 인스턴스를 생성할 때 Javascript 내부에서 호출되는 메서드입니다.

class User {
  constructor(name, age, tech) { // User 클래스의 생성자
    this.name = name;
    this.age = age;
    this.tech = tech;
  }
}

const user = new User("이용우", 28, "Node.js"); // user 인스턴스 생성

console.log(user.name); // 이용우
console.log(user.age); // 28
console.log(user.tech); // Node.js

this와 프로퍼티(Property)

생성자의 바디에서 this 키워드를 사용합니다. 이 this는 클래스를 사용해 만들어 질 객체 자신을 의미하고 this 뒤에 붙는 name, age, tech는 클래스를 이용해서 만들어질 객체의 속성(Propety)입니다.

 

메서드(Method)

자바스크립트에서 사용할 수 있는 모든 값은 프로퍼티 값으로 사용할 수 있습니다.

프로퍼티 값이 함수일 경우에는 일반 함수와 구분하기 위해 메서드(Method)라고 부릅니다.

즉, 메서드는 객체(Object) 에 묶여 있는 함수를 의미합니다.

클래스 내에서 만든 함수는 메서드다! 라고 볼수있습니다.

class User {
  constructor(name, age, tech) { // User 클래스의 생성자
    this.name = name;
    this.age = age;
    this.tech = tech;
  }

  getName() { return this.name; } // getName 메서드
  getAge() { return this.age; }.  // getAge 메서드
  getTech() { return this.tech; } // getTech 메서드
}

const user = new User("이용우", "28", "Node.js"); // user 인스턴스 생성
console.log(user.getName()); // 이용우
console.log(user.getAge()); // 28
console.log(user.getTech()); // Node.js

상속

일반적으로 클래스의 인스턴스는 선언한 클래스의 기능을 모두 상속합니다.

상속을 이용해 부모 클래스자식 클래스로 나뉠 수 있는데요.

부모 클래스의 경우 메서드, 내부 변수와 같은 정보를 자식 클래스에게 할당해줄 수 있습니다.

class User { // User 부모 클래스
  constructor(name, age, tech) { // 부모 클래스 생성자
    this.name = name;
    this.age = age;
    this.tech = tech;
  }
  getTech(){ return this.tech; } // 부모 클래스 getTech 메서드
}

class Employee extends User{ // Employee 자식 클래스
  constructor(name, age, tech) { // 자식 클래스 생성자
    super(name, age, tech);
  }
}

const employee = new Employee("이용우", "28", "Node.js");
console.log(employee.name); // 이용우
console.log(employee.age); // 28
console.log(employee.getTech()); // 부모 클래스의 getTech 메서드 호출: Node.js

 

클래스 퀴즈

class Unit {
  constructor(name, hp) {
    this.name = name;
    this.hp = hp;
  }
  healing(heal) {
    if (this.hp <= 0) return;
    this.hp += heal;
    if (this.hp >= 100) this.hp = 100;
  }
  damaged(damage) {
    if (this.hp <= 0) return;
    this.hp -= damage;
    if (this.hp <= 0) this.hp = 0;
  }
}

const unit = new Unit('유닛', 100);
unit.damaged(70); // 30
unit.healing(10); // 40
unit.damaged(50); // 0
unit.healing(100); // 0

 

다시 한번 요약정리 (https://bit.ly/3VTSzeA)

 

블로킹/논블로킹

= 요청받는 함수가 제어권(함수실행권)을 언제 넘겨주느냐의 차이

  • 블로킹 : 요청받는 함수가 작업을 모두 마치고 나서야 요청자에게 제어권을 넘겨줌              
                  (그동안 요청자는 아무것도 하지않고 기다림)
  • 논블로킹 : 요청받은 함수가 요청자에게 제어권을 바로 넘겨줌 (그동안 요청자는 다른 일을 할 수 있음)

 

동기/비동기

= 요청받은 함수가 작업을 완료했는지를 체크해서 순차적 흐름의 차이

  • 동기 : 요청자가 요청받은 함수의 작업이 완료되었는지 계속 확인 (여러 함수들이 시간을 맞춰 실행됨)
  • 비동기 : 요청자는 요청후 신경X, 요청받은 함수가 작업을 마치면 알려줌               (함수들의 작업 시작/종료 시간이 맞지 않을수도)
728x90

+ Recent posts