객체 지향 프로그래밍(OOP)

객체 지향 프로그래밍 (Object Oriented Programming)은 객체를 중심으로 프로그램을 설계하고 구현하는 방법론이다. 자바스크립트에서 OOP는 클래스와 인스턴스, 생성자 함수, 상속 그리고 프로토타입 개념을 통해서 구현된다.

 

클래스와 인스턴스

클래스는 객체를 생성하기 위한 블루프린트 또는 템플릿이다. 클래스는 속성과 메서드를 정의하며, 인스턴스는 클래스를 기반으로 생성된 객체를 의미한다.

 

클래스

ES6 이전에는 자바스크립트에서 클래스를 정의하기 위해 생성자 함수와 프로토타입을 사용했다. 이후에는 'class' 키워드가 추가되어 키워드를 사용하여 클래스를 정의할 수 있게 되었다.

 

클래스 정의

class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }

    greet() {
        console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
    }
}

// 인스턴스 생성
const bak = new Person('Bak', 30);
bak.greet(); // "Hello, my name is Bak and I am 30 years old."

 

생성자 함수

생성자 함수는 클래스를 정의하는 전통적인 방법으로 'new' 키워드를 사용하여 생성자 함수를 호출하면 새로운 인스턴스가 생성된다.

function Person(name, age) {
    this.name = name;
    this.age = age;
}

Person.prototype.greet = function() {
    console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
};

// 인스턴스 생성
const bak = new Person('Bak', 25);
bak.greet(); // "Hello, my name is Bak and I am 25 years old."

 

상속과 프로토타입

상속은 한 클래스가 다른 클래스의 속성과 메서드를 상속받아 사용하는 개념이다. 자바스크립트에서는 프로토타입 기반 상속을 사용한다. 자바스크립트의 모든 객체는 프로토타입 객체를 가지고 있으며, 다른 객체로부터 메서드와 속성을 상속받을 수 있다.

 

클래스 상속

ES6에서는 'extends' 키워드를 사용하여 상속을 구현할 수 있다.

class Animal {
    constructor(name) {
        this.name = name;
    }

    speak() {
        console.log(`${this.name} makes a noise.`);
    }
}

class Dog extends Animal {
    constructor(name, breed) {
        super(name); // 부모 클래스의 생성자를 호출
        this.breed = breed;
    }

    speak() {
        console.log(`${this.name} barks.`);
    }
}

const rex = new Dog('Rex', 'Labrador');
rex.speak(); // "Rex barks."

 

프로토타입 상속

ES6 이전에는 프로토타입을 사용하여 상속을 구현하였다.

function Animal(name) {
    this.name = name;
}

Animal.prototype.speak = function() {
    console.log(`${this.name} makes a noise.`);
};

function Dog(name, breed) {
    Animal.call(this, name); // 부모 생성자 호출
    this.breed = breed;
}

Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

Dog.prototype.speak = function() {
    console.log(`${this.name} barks.`);
};

const rex = new Dog('Rex', 'Labrador');
rex.speak(); // "Rex barks."

 

상속의 이점

상속의 특징을 제대로 이해하고 적절한 상황에 맞게 활용하는 것이 중요하다.

 

코드 재사용성

상속을 통해 기존 클래스의 기능을 재사용할  수 있기 때문에 이를 통해 중복 코드를 줄이고 새로운 기능을 쉽게 추가할 수 있다.

class Animal {
    constructor(name) {
        this.name = name;
    }

    speak() {
        console.log(`${this.name} makes a noise.`);
    }
}

class Dog extends Animal {
    speak() {
        console.log(`${this.name} barks.`);
    }
}

const dog = new Dog('Rex');
dog.speak(); // "Rex barks."

 

'Dog' 클래스는 'Animal' 클래스의 'name' 속성과 'speak' 메서드를 재사용하여 기능을 확장한다.

 

코드의 가독성과 유지보수성 향상

상속으로 클래스 간의 관계를 명확히 하고, 코드를 더 구조적이고 일관성 있게 작성하여 코드의 가독성을 높이고 유지보수를 쉽게 할 수 있다.

class Shape {
    constructor(color) {
        this.color = color;
    }

    draw() {
        console.log('Drawing a shape');
    }
}

class Circle extends Shape {
    constructor(color, radius) {
        super(color);
        this.radius = radius;
    }

    draw() {
        super.draw();
        console.log(`Drawing a circle with radius ${this.radius}`);
    }
}

const circle = new Circle('red', 5);
circle.draw();
// "Drawing a shape"
// "Drawing a circle with radius 5"

 

'circle' 클래스는 'shape' 클래스를 상속받아 'color' 속성과 'draw' 메서드를 재사용하고 필요한 기능을 추가한다. 이를 통해서 코드가 더 구조적이고 명확해지도록 할 수 있다.

 

다형성(Polymorphism)

다형성은 같은 메서드가 다양한 클래스에서 다른 방식으로 동작하도록 하는 것으로 코드의 유연성을 높일 수 있다.

class Animal {
    speak() {
        console.log('Animal makes a noise');
    }
}

class Dog extends Animal {
    speak() {
        console.log('Dog barks');
    }
}

class Cat extends Animal {
    speak() {
        console.log('Cat meows');
    }
}

function makeAnimalSpeak(animal) {
    animal.speak();
}

const dog = new Dog();
const cat = new Cat();

makeAnimalSpeak(dog); // "Dog barks"
makeAnimalSpeak(cat); // "Cat meows"

 

'makeAnimalSpeak' 함수는 'Animal' 클래스를 상속받는 객체를 인수로 받아 다형성을 통해 다양한 동작을 수행할 수 있다.

 

클래스 간의 계층 구조 정의

상속 구조는 클래스 간의 계층 구조를 정의할 수 있어 복잡한 시스템을 더 쉽게 이해하고 관리할 수 있다.

class Vehicle {
    constructor(brand) {
        this.brand = brand;
    }

    start() {
        console.log('Starting the vehicle');
    }
}

class Car extends Vehicle {
    constructor(brand, model) {
        super(brand);
        this.model = model;
    }

    start() {
        super.start();
        console.log(`Starting the car ${this.brand} ${this.model}`);
    }
}

const car = new Car('Toyota', 'Corolla');
car.start();
// "Starting the vehicle"
// "Starting the car Toyota Corolla"

 

'vehicle' 클래스는 기본적인 차량의 속성과 메서드를 정의하고, 'Car' 클래스는 이를 상속받아 구체적인 차량 모델을 정의한다. 이는 클래스 간의 관계를 명확히 하고 계층 구조를 쉽게 이해할 수 있다.

 

객체 간의 관계 모델링

상속을 사용하면 객체 간의 관계를 모델링하여 복잡한 시스템을 설계하고 구현하는 데 유용하다.

class Employee {
    constructor(name, position) {
        this.name = name;
        this.position = position;
    }

    work() {
        console.log(`${this.name} is working as a ${this.position}`);
    }
}

class Manager extends Employee {
    constructor(name, department) {
        super(name, 'Manager');
        this.department = department;
    }

    manage() {
        console.log(`${this.name} is managing the ${this.department} department`);
    }
}

const manager = new Manager('Bak', 'Sales');
manager.work(); // "Bak is working as a Manager"
manager.manage(); // "Bak is managing the Sales department"

 

'manager' 클래스는 'Employee' 클래스를 상속받아 관리자의 속성과 메서드를 정의하여 객체 간의 관계를 명확히 모델링할 수 있다.

 

상속은 객체 지향 프로그래밍에서 매우 유용한 개념이지만 과도하게 또는 잘못된 방식으로 사용하게 되면 오히려 코드의 복잡성을 증가시켜 유지보수를 어렵게 만들 수 있다.

728x90
반응형

'Program Language > JavaScript' 카테고리의 다른 글

this  (0) 2024.08.26
JavaScript #17 고차 함수(High-order Function)  (2) 2024.07.24
JavaScript #15 비동기 자바스크립트  (0) 2024.07.23
JavaScript #14 ES6+ 문법  (4) 2024.07.23
JavaScript #13 DOM(Document Object Model)  (0) 2024.07.23

비동기

비동기는 시간이 걸리는 네트워크 요청, 파일 읽기 등을 수행할 때 코드의 실행을 차단하지 않고 비동기적으로 처리할 수 있게 해주는 중요한 개념이다. 자바스크립트의 비동기와 관련된 기능들은 웹 애플리케이션을 더 빠르고 반응성이 좋게 동작하게 한다.

 

콜백 함수

콜백 함수는 다른 함수의 인수로 전달되는 함수이다.

비동기 작업이 완료되면 호출되며 비동기 작업을 처리하는 가장 기본적인 방법이다.

function fetchData(callback) {
    setTimeout(() => {
        const data = { id: 1, name: 'John Doe' };
        callback(data);
    }, 1000); // 1초 후에 콜백 함수 호출
}

fetchData((data) => {
    console.log('Data received:', data);
});

 

여기서 fetchData 함수는 1초 후에 데이터를 콜백 함수에 전달한다. 이 방식은 간단하지만, 여러 비동기 작업이 중첩될 경우 콜백 지옥이라 불리는 가독성이 떨어지는 코드가 될 위험이 있다.

 

프로미스

프로미스는 비동기 작업의 완료 또는 실패를 처리하는 객체이다. then, catch, finally 메서드를 사용하여 비동기 작업의 결과를 처리한다.

function fetchData() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            const data = { id: 1, name: 'John Doe' };
            resolve(data); // 성공적으로 데이터를 반환
        }, 1000);
    });
}

fetchData()
    .then((data) => {
        console.log('Data received:', data);
    })
    .catch((error) => {
        console.error('Error:', error);
    });

 

프로미스를 사용하면 코드의 가독성이 개선되고, 여러 비동기 작업을 체인으로 연결하여 처리할 수 있다. 프로미스가 성공적으로 완료될 때 resolve가 호출되며 'value'에는 성공적으로 완료된 후 전달되는 값이다. 실패할 경우 reject가 호출되며 'reason'은 프로미스가 실패한 이유를 나타내는 값이다.

 

프로미스는 대기(pending), 이행(fulfilled), 거부(rejected) 세 가지 상태를 가질 수 있다.

 

대기

프로미스가 생성된 초기 상태로 'then', 'catch', 'finally' 메서드가 아직 호출되지 않은 상태이다.

 

이행

프로미스가 성공적으로 완료된 상태로 'then' 메서드가 호출된다.

 

거부

프로미스가 실패한 상태로 'catch' 메서드가 호출된다.

 

프로미스가 이행, 거부 상관없이 작업이 완료되었을 때 항상 'finally'가 호출된다. 보통 프로미스의 상태에 상관없이 반드시 실행되어야 하는 리소스를 해제, 로딩 상태를 해제하는 등의 작업 같은 코드를 작성할 때 사용된다.

const myPromise = new Promise((resolve, reject) => {
  let success = true; // 작업 성공 여부를 결정하는 변수
  
  setTimeout(() => {
    if (success) {
      resolve("작업이 성공적으로 완료되었습니다!"); // 이행 상태로 전환
    } else {
      reject("작업이 실패했습니다."); // 거부 상태로 전환
    }
  }, 1000); // 1초 후에 상태 결정
});

myPromise
  .then((value) => {
    console.log("이행됨:", value); // 프로미스가 이행되면 실행
  })
  .catch((reason) => {
    console.log("거부됨:", reason); // 프로미스가 거부되면 실행
  })
  .finally(() => {
    console.log("프로미스가 완료됨."); // 프로미스가 완료되면 항상 실행
  });

 

async, await

async와 await 키워드는 ES2017에서 도입된 비동기 프로그래밍의 최신 방법이다.

async 함수는 항상 프로미스를 반환하며, await 키워드는 프로미스가 처리될 때까지 함수의 실행을 일시 중지한다. 이를 통해 비동기 코드를 동기식 코드처럼 작성할 수 있게 된다.

function fetchData() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            const data = { id: 1, name: 'John Doe' };
            resolve(data); // 성공적으로 데이터를 반환
        }, 1000);
    });
}

async function getData() {
    try {
        const data = await fetchData(); // 프로미스가 처리될 때까지 대기
        console.log('Data received:', data);
    } catch (error) {
        console.error('Error:', error);
    }
}

getData();

 

동기식처럼 처리되는 코드처럼 보이면서도 async, await 키워드를 사용해서 비동기적으로 동작하게 한다.

 

콜백 지옥 (Callback Hell)

콜백 지옥은 자바스크립트에서 비동기 작업을 중첩된 콜백 함수로 처리할 때 발생하는 문제로, 코드의 가독성과 유지보수성이 크게 떨어지는 현상을 말한다.

function authenticateUser(username, password, callback) {
    setTimeout(() => {
        console.log('User authenticated');
        callback(null, { userId: 1, username: username });
    }, 1000);
}

function fetchUserData(userId, callback) {
    setTimeout(() => {
        console.log('User data fetched');
        callback(null, { userId: userId, data: 'Some user data' });
    }, 1000);
}

function processData(data, callback) {
    setTimeout(() => {
        console.log('Data processed');
        callback(null, { processedData: 'Processed data' });
    }, 1000);
}

authenticateUser('user1', 'password123', (authError, authData) => {
    if (authError) {
        console.error('Authentication error:', authError);
        return;
    }
    fetchUserData(authData.userId, (fetchError, userData) => {
        if (fetchError) {
            console.error('Fetch error:', fetchError);
            return;
        }
        processData(userData.data, (processError, processedData) => {
            if (processError) {
                console.error('Processing error:', processError);
                return;
            }
            console.log('All tasks completed successfully:', processedData);
        });
    });
});

 

'authenticateUser' 함수는 사용자를 인증하고 결과를 콜백 함수에 전달한다.

인증이 성공하면 'fetchUserData' 함수가 호출되어 사용자 데이터를 가져온다. 

사용자 데이터가 성공적으로 가져오면, 'processData' 함수가 호출되어 데이터를 처리한다.

 

위 코드는 각 단계별로 성공 여부를 대기하고 성공 시 다음 단계로 넘어가는 구조이다. 이러한 구조를 중첩된 콜백 함수라고 하며 코드가 길어지고 복잡해져 가독성이 떨어진다는 것이 확인된다. 가독성이 떨어지면 유지보수와 에러 처리에도 어려움이 발생할 수밖에 없다.

 

이를 예방하는 방법으로는 위에서 서술된 프로미스 사용, async, await 키워드를 사용하는 방법들이 있고 그 밖에도 몇 가지 방법들이 존재한다.

 

이름이 있는 함수로 콜백 분리

익명 함수 대신 이름이 있는 함수를 사용하여 콜백을 분리하면 코드의 가독성과 재사용성이 향상된다.

function fetchData() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            const data = { id: 1, name: 'John Doe' };
            resolve(data);
        }, 1000);
    });
}

fetchData()
    .then(data => {
        console.log('Data received:', data);
        return fetchData(); // 다음 비동기 작업
    })
    .then(data => {
        console.log('Next data received:', data);
    })
    .catch(error => {
        console.error('Error:', error);
    });

 

모듈화 및 함수 분리

비동기 작업을 여러 작은 함수로 나누고 모듈화 하면 코드가 더 관리하기 쉬워진다.

function fetchData() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            const data = { id: 1, name: 'John Doe' };
            resolve(data);
        }, 1000);
    });
}

async function handleFirstData() {
    try {
        const data = await fetchData();
        console.log('Data received:', data);
        return data;
    } catch (error) {
        console.error('Error in handleFirstData:', error);
    }
}

async function handleSecondData() {
    try {
        const data = await fetchData();
        console.log('Next data received:', data);
        return data;
    } catch (error) {
        console.error('Error in handleSecondData:', error);
    }
}

async function processAllData() {
    await handleFirstData();
    await handleSecondData();
}

processAllData();

 

비동기 제어 라이브러리 사용

비동기 제어 흐름을 관리하기 위해 'async.js'와 같은 비동기 작업을 관리하는 데 유용한 유틸리티를 제공하는 라이브러리를 사용할 수 있다.

 

async.js 등 라이브러리를 사용하기 위해서는 설치가 필요하다.

<script src="https://cdnjs.cloudflare.com/ajax/libs/async/3.2.0/async.min.js"></script>

 

node.js 환경에서는 npm install async를 사용하여 설치할 수 있다.

npm install async

 

async.js 사용법

시퀀스 작업 처리

'async.series'를 사용하여 비동기 작업을 순차적으로 처리할 수 있다.

const async = require('async');

function fetchData(callback) {
    setTimeout(() => {
        console.log('Data fetched');
        callback(null, { id: 1, name: 'John Doe' });
    }, 1000);
}

function processData(data, callback) {
    setTimeout(() => {
        console.log('Data processed:', data);
        callback(null, { processedData: true });
    }, 1000);
}

async.series([
    function(callback) {
        fetchData(callback);
    },
    function(callback) {
        fetchData((err, data) => {
            if (err) return callback(err);
            processData(data, callback);
        });
    }
], function(err, results) {
    if (err) {
        console.error('Error:', err);
    } else {
        console.log('All tasks completed:', results);
    }
});

 

병렬 작업 처리

'async.parallel'을 사용하여 비동기 작업을 병렬로 처리할 수 있다.

const async = require('async');

function fetchData1(callback) {
    setTimeout(() => {
        console.log('Data1 fetched');
        callback(null, { id: 1, name: 'John Doe' });
    }, 1000);
}

function fetchData2(callback) {
    setTimeout(() => {
        console.log('Data2 fetched');
        callback(null, { id: 2, name: 'Jane Doe' });
    }, 500);
}

async.parallel([
    function(callback) {
        fetchData1(callback);
    },
    function(callback) {
        fetchData2(callback);
    }
], function(err, results) {
    if (err) {
        console.error('Error:', err);
    } else {
        console.log('All tasks completed in parallel:', results);
    }
});

 

각 작업 처리

'async.each'를 사용하여 배열의 각 요소에 대해 비동기 작업을 수행할 수 있다.

const async = require('async');

const items = [1, 2, 3, 4, 5];

function processItem(item, callback) {
    setTimeout(() => {
        console.log('Processed item:', item);
        callback(null, item);
    }, 1000);
}

async.each(items, processItem, function(err) {
    if (err) {
        console.error('Error:', err);
    } else {
        console.log('All items processed');
    }
});

 

728x90
반응형

ES6+

ECMAScript 6부터의 버전에서는 자바스크립트 언어에 여러 유용한 기능들이 추가되었다. 

 

이 중에서도 특히 중요한 템플릿 리터럴, 디스트럭처링 할당, 스프레드 연산자와 나머지 매개변수, 모듈화에 대해서 정리한다.

 

템플릿 리터럴 (Template Literals)

템플릿 리터럴은 백틱을 사용하여 문자열을 작성하며, 문자열 내에 표현식을 포함할 수 있는 기능을 제공한다.

 

기본 사용법

const name = 'Bak';
const greeting = `Hello, ${name}!`; // 표현식 ${}을 사용
console.log(greeting); // "Hello, Bak!"

 

${} 표현식을 사용해서 문자열 내에서 직접 변수의 값에 바로 접근할 수 있다.

 

여러 줄 문자열

템플릿 리터럴을 사용하면 여러 줄에 걸쳐 문자열을 작성할 수 있다.

const multiline = `This is
a string
that spans multiple lines.`;
console.log(multiline);

 

ES6 이전에는 문자열을 쓸 때 큰따옴표를 사용해야 했으며 백틱을 사용하게 되면 구문 오류(Syntax Error)가 발생한다.

 

그리고 이전의 자바스크립트는 한 줄로 작성된 문자열을 인식하기 때문에 여러 줄에 걸쳐 문자열을 작성하기 위해서는 줄 끝에 백슬래시를 사용하여 줄 바꿈을 나타내야 했다.

 

var multiLineString = "This is the first line \
This is the second line \
This is the third line";
console.log(multiLineString);
// "This is the first line This is the second line This is the third line"

// 또는 

var multiLineString = "This is the first line\n" +
                      "This is the second line\n" +
                      "This is the third line";
console.log(multiLineString);
// This is the first line
// This is the second line
// This is the third line

 

이런 방법들은 코드의 가독성을 떨어뜨릴 여지가 충분했다.

 

디스트럭처링 할당 (Destructuring Assignment)

디스트럭처링 할당은 배열이나 객체의 값을 개별 변수로 쉽게 추출할 수 있게 해주는 문법이다. 이는 코드를 더 간결하고 가독성 좋게 만들며, 특히 복잡한 데이터 구조를 다룰 때 유용하다. 

 

const numbers = [1, 2, 3, 4];
const [first, second, ...rest] = numbers; // 배열의 첫 두 요소를 추출하고 나머지는 rest에 할당
console.log(first); // 1
console.log(second); // 2
console.log(rest); // [3, 4]

 

객체 디스트럭처링

const person = {
    name: 'Bob',
    age: 30,
    job: 'developer'
};
const { name, age, job } = person; // 객체의 프로퍼티를 개별 변수로 추출
console.log(name); // 'Bob'
console.log(age); // 30
console.log(job); // 'developer'

 

중첩된 구조 디스트럭처링

const person = {
    name: 'Charlie',
    address: {
        city: 'New York',
        zip: '10001'
    }
};
const { name, address: { city, zip } } = person; // 중첩된 구조에서 프로퍼티 추출
console.log(name); // 'Charlie'
console.log(city); // 'New York'
console.log(zip); // '10001'

 

함수 파라미터에서 디스트럭처링

함수 파라미터에서 디스트럭처링을 사용하면 코드가 더 직관적이고 명확해진다.

function displayPerson({ name, age }) {
  console.log(`Name: ${name}, Age: ${age}`);
}

const person = { name: 'Bak', age: 25 };
displayPerson(person); // Name: Bak, Age: 25

 

디스트럭처링을 잘 활용하면 코드의 유지보수성을 높이고, 가독성을 개선하며, 실수를 줄이는 데 도움이 된다. 

 

스프레드 연산자 (Spread Operator)

스프레드 연산자('...')는 세 개의 점으로 표현된다.

 

배열이나 객체를 펼치거나, 함수의 나머지 매개변수로 사용할 수 있어 배열이나 객체를 보다 간결하고 직관적으로 다룰 수 있게 해 준다.

 

배열에서 스프레드 연산자

// 배열 복사
const arr1 = [1, 2, 3];
const arr2 = [...arr1];
console.log(arr2); // [1, 2, 3]

// 배열 결합
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2]; // 배열을 펼쳐서 결합
console.log(combined); // [1, 2, 3, 4, 5, 6]

 

객체에서의 스프레드 연산자

// 객체 복사
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1 };
console.log(obj2); // { a: 1, b: 2 }

// 객체 결합
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3, d: 4 };
const combinedObj = { ...obj1, ...obj2 }; // 객체를 펼쳐서 결합
console.log(combinedObj); // { a: 1, b: 2, c: 3, d: 4 }

 

배열이나 객체를 단순히 변수에 대입하는 것과 스프레드 연산자를 사용하여 복사하는 것은 중요한 차이가 있다.

변수 대입과 참조

자바스크립트에서 배열이나 객체를 변수에 대입할 때 실제로는 해당 배열이나 객체의 참조가 복사된다. 이는 두 변수가 같은 배열이나 객체를 참조하게 된다는 의미로 한 변수를 통해 배열이나 객체를 변경하면, 다른 변수에도 그 변경 사항이 반영된다.

 

 

나머지 매개변수 (rest parameters)

함수에서 가변 인자를 처리할 수 있도록 도와주는 기능이다. 이 기능은 보다 인자들을 유연하게 다룰 수 있게 된다.

function sum(...args) { // 나머지 매개변수로 모든 인수를 배열로 받음
    return args.reduce((total, current) => total + current, 0);
}
console.log(sum(1, 2, 3)); // 6
console.log(sum(4, 5, 6, 7)); // 22

 

나머지 매개변수를 사용하면 함수가 전달받는 인자의 수에 제한이 없어 특히 가변 인자를 처리해야 하는 상황에서 유용하다.

function concatenate(separator, ...strings) {
  return strings.join(separator);
}

console.log(concatenate(', ', 'Hello', 'World', 'JavaScript')); // "Hello, World, JavaScript"
console.log(concatenate(' - ', 'Learn', 'Code', 'Enjoy')); // "Learn - Code - Enjoy"

 

배열 메서드를 직접 사용할 수 있어 가변 인자를 처리하는 로직이 명확해져 가독성이 높아지고 가변 인자를 처리하기 위한 별도의 코드를 작성할 필요가 없어 중복 코드를 줄일 수 있다.

 

arguments 

전통적으로 자바스크립트에서는 arguments 객체를 사용하여 함수의 모든 인자를 접근할 수 있다. 하지만 arguments 객체는 배열이 아니기 때문에 배열 메서드를 직접 사용할 수 없어 추가적인 변환 작업을 필요로 한다.

function oldSum() {
  const args = Array.prototype.slice.call(arguments);
  return args.reduce((total, num) => total + num, 0);
}

console.log(oldSum(1, 2, 3)); // 6

 

반면 나머지 매개변수는 배열로 제공되기 때문에 배열 메서드를 바로 사용할 수 있어 더 직관적이고 간편하다.

 

모듈화 (Modules)

모듈화를 통해 코드를 여러 파일로 나눠서 관리할 수 있어 코드의 재사용성과 유지보수성을 높여준다.

 

모듈 내보내기/가져오기 (Export/Import)

모듈에서 함수를 내보내는 두 가지 방법이 있다. 

 

name exports

모듈에서 여러 개의 변수를 내보낼 수 있으며, 각 변수를 특정 이름으로 내보낸다. 가져올 때는 내보낸 이름을 사용하여 모듈을 가져와야 한다.

// math.js
export const pi = 3.14;
export function add(x, y) {
  return x + y;
}
export class Calculator {
  subtract(x, y) {
    return x - y;
  }
}

 

import

// main.js
import { pi, add, Calculator } from './math.js';

console.log(pi); // 3.14
console.log(add(2, 3)); // 5
const calc = new Calculator();
console.log(calc.subtract(5, 3)); // 2

 

name export의 경우 같은 이름을 가진 변수가 이미 사용 중이라면 이름 충돌이 발생하기도 한다. 이를 해결하기 위해서 as 키워드를 사용하여 별칭을 붙일 수 있다.

import { add as addNumbers } from './math.js';

 

default exports

모듈에서 하나의 기본 값을 내보낸다. 모듈당 하나의 default export만 가질 수 있으며 이름 없이 내보낼 수 있다.

// utils.js
export default function greet(name) {
  return `Hello, ${name}!`;
}

 

import

// main.js
import greet from './utils.js';

console.log(greet('Bak')); // Hello, Bak!

 

혼합 사용

하나의 모듈에서 named exports와 default export를 동시에 사용할 수 있다.

// module.js
export const pi = 3.14;
export function add(x, y) {
  return x + y;
}
export default function subtract(x, y) {
  return x - y;
}

// main.js
import subtract, { pi, add } from './module.js';

console.log(pi); // 3.14
console.log(add(2, 3)); // 5
console.log(subtract(5, 3)); // 2
728x90
반응형

+ Recent posts