1. 함수 다루기

1) 함수, 메서드, 생성자

  • 함수, 메서드, 생성자를 실전에서 자주 사용하면서도 막상 각 기능들을 정의하며 제대로 사용해볼 수 있는 여유는 없었던 것 같다.
1-1) 함수의 정의
  • 1급 객체
  • 변수나, 데이터에 담길 수 있음
  • 매개변수로 전달 가능 (콜백 함수)
  • ※ 콜백 함수 란, 다른 함수에 인자로 전달되는 함수를 말한다. 비동기적인 프로그래밍에서 유용하며, JS와 같은 언어에서 일반적인 패턴.
  • 함수가 함수를 반환 할 수 있음 (고차 함수의 경우)
// 콜백 함수 예시
const numbers = [1, 2, 3];
// 함수 doubled 가 인자로 사용되고 있음. doubled를 콜백함수라고 함.
const doubled = numbers.map((number) => {
    return number * 2;
})

console.log(doubled) // [2, 4, 6]
1-2) 메소드의 정의
  • 객체에 의존성이 있는 함수, OOP 행동을 의미
  • ※ OOP 란, 프로그램을 객체들의 집합으로 보고 이들 간의 상호작용으로 서술하는 접근법을 말함
// 메소드 예시
const obj = {
    // method: (e) => {
    //     return 'helloWorld'
    // }

    // concise method 적용
    method(e) {
        return 'helloWorld'
    }
}

console.log(obj.method());

2) argument & parameter

  • argument(인자): 함수를 콜하는 곳에 위치, 실제로 사용되는 값.
  • parameter: 함수를 정의하는 곳에 위치, 형식을 갖춘 변수.
const example = (parameter) => {
    console.log(parameter);
}

const argument = 'foo';

example(argument);

3) 복잡한 인자 관리하기

  • 함수를 정의할 때, 사용자 측에서 맥락을 이해하도록 매개변수의 이름을 명료하게 작성하는게 좋다.
// 예제 1
// 함수명과 매개변수명을 참고
const toggleDisplay = (isToggle) => {
    // ... some code
}

const getRandomNumber = (min, miax) => {
    // ... some code
}

const timer = (start, stop, end) => {
    // ... some code
}

const genSquare = (top, right, bottom, left) => {
    // ... some code
}
  • 아래와 같이 매개변수를 구조분할로 작성하면, 사용자에게 필수 params를 알려주고 인자를 안전하게 사용할 수 있게 할 수 있다. (적극 추천)
// 예제 2
// 요구사항: 차량 소유자 확인에 필요한 정보(이름, 차량번호)와 옵션 정보(brand, type) 함수를 정의하라
const createCar = ({ name, carNumber, type, brand }) => {
    if (!name) {
        throw new Error('name is a required');
    }

    if (!carNumber) {
        throw new Error('brand is a required');
    }

    return {
        name,
        carNumber,
        type,
        brand
    }
}

console.log(createCar({ carNumber: 2810, type: "세단", brand: "K5" })) // Error: name is a required
console.log(createCar({ name: "이동규", carNumber: 2810, type: "세단", brand: "K5" })); // { name: '이동규', carNumber: 2810, type: '세단', brand: 'K5' }

4) Default Value

  • Default Value를 포함하여 매개변수를 작성하면, 값이 undefined 되었을 때 발생할만한 문제를 방어할 수 있다.
  • 그런데, Default Value를 ll 연산자로 지정하면 예제 1과 같이 코드 작성이 번거로울 수 있는데, 이를 예제 2와 같이 단축할 수도 있다.
// 예제 1
const createCarousel = (options) => {
    options = options || {};
    const margin = options.margin || 0;
    const center = options.center || false;
    const navElement = options.navElement || 'div';

    return {
        margin,
        center,
        navElement
    }
}

// { margin: 0, center: false, navElement: 'div' }
console.log(createCarousel()); 
// 예제 2
// 매개변수가 객체로 들어옴
const createCarousel = (
    {
        // default value
        margin = 0,
        center = false,
        navElement = 'div',
        // '= {}' 는 'options = options || {};' 코드와 동일함
        // '= {}' 가 없으면 코드 에러
    } = {}) => {
    return {
        margin,
        center,
        navElement
    }
}

// { margin: 0, center: false, navElement: 'div' }
console.log(createCarousel());

5) Rest Parameters

  • 가변 인자가 들어오는 경우, 즉 몇 개의 인자가 사용될지 모르는 경우, 함수의 매개변수를 정의할 때 ‘Rest parameters(…)’를 사용하여 해결할 수 있다.
  • 단, 여기서 ‘…‘는 스프레드 연산자와 다르니 주의하도록 하자.
  • 이 때, Rest Parameters로 들어온 데이터의 타입은 ‘Array’이므로 배열 메소드를 사용할 수 있다는 점도 기억하자.
// 예제 1
const sumTotal = (...params) => {
    // Rest Parameters의 타입은 Array
    console.log(Array.isArray(params)); // true

    // 배열 메소드 바로 사용 가능
    return params.reduce(
        (acc, curr) => acc + curr
    );
}

console.log(sumTotal(1, 2, 3, 4, 5));

Rest Parameters에서 첫번째, 두번째 인자를 받아보고 싶은 경우, 아래와 같이 순서에 맞는 위치에 매개 변수를 지정하면 받아볼  있다.

  • Rest Parameters에서 첫번째, 두번째 인자를 받아보고 싶은 경우, 아래와 같이 순서에 맞는 위치에 매개 변수를 지정하면 받아볼 수 있다.
// 예제 2
const sumTotal = (first, second, ...params) => {
    return {
        first,
        second,
        rest: params
    }
}

console.log(sumTotal(1, 2, 3, 4, 5)); // { first: 1, second: 2, rest: [ 3, 4, 5 ] }

6) void & return

  • JS의 함수에서 return이 없는 함수는 기본적으로 ‘undefined’를 리턴한다.
  • 당연한 이야기지만, 함수 선언 시 불필요하게 return 을 사용하지 않는 편이 좋다.
// return 이 없는 함수를 호출하는 경우
const isAdult = (age) => {
    const res = age > 19;
}

console.log(isAdult(20)); // undefined


JS에도 voide가 있는데, 때에 따라 아래와 같이 링크를 클릭했을 , 어떠한 경로로 이동하지 않도록   사용할 수도 있다.
<a href="javascript:void(0)">Link</a>

7) 화살표 함수

  • 실무에서 화살표 함수를 많이 쓰는데, 맹목적으로 사용하는 경우 문제가 발생할 수 있다.
  • 리액트가 아닌 다른 개발 환경(Node.js)에서는 화살표 함수를 맹목적으로 사용하지 않도록 주의하자.
// 주의 1 - 객체의 메소드로 화살표 함수를 사용하는 경우
const user = {
    name: '홍길동',
    getName: () => {
        return this.name;
    }
};

console.log(user.getName()); // undefined, 오류

// 개선 1 - 객체의 메소드를 정의하는 경우, 화살표 함수 금지
const user = {
    name: '홍길동',
    getName() {
        return this.name;
    }
};

console.log(user.getName()); // 홍길동

// 주의 2 - 화살표 함수 형식으로 정의하면 생성자(new)를 사용할 수 없음
const Person = (name, city) => {
    this.name = name;
    this.city = city;
}

const person = new Person("홍길동", "서울"); // Person is not a constructor, 오류

8) 콜백 함수

  • 콜백 함수는 Promise와 async, await으로 바뀌는 비동기로 제어하는 기법으로 볼 수 있다.
  • 그리고 어떠한 함수의 실행권을 다른 함수로 넘겨주는 것으로 볼 수 있다.
const btnHandler = () => {
    console.log("버튼이 눌렸습니다.")
}

// 콜백함수(btnHandler)의 실행권을 사용자에게 넘기는 것으로 볼 수 있음
window.addEventListener('click', btnHandler);

  • 콜백 함수를 이용하면, 코드를 리펙토링할 때 도움이 될 수 있다.
  • 주의) 콜백 함수를 argument로 사용하는 경우, 함수명만 호출하도록 한다. 일반적인 함수호출 방식(‘함수명 + ()’)의 경우가 아닌 함수의 이름을 그대로 받아 전달받게 해야한다.
// 예시 - 콜백 함수로 리팩토링 전
function register() {
    const isConfirm = confirm(
        "회원가입에 성공했습니다."
    );

    if (isConfirm) {
        redirecUserInfoPage();
    }
}

function login() {
    const isConfirm = confirm(
        "로그인에 성공했습니다."
    )

    if (isConfirm) {
        redirectIndexPage();
    }
}
// 개선 - 콜백 함수(confirmModal)로 리팩토링 후
// message가 참이면, 전달받은 함수를 실행
function confirmModal(message, cbFunc) {
    const isConfirm = confirm(message);

    if (isConfirm && cbFunc) {
        cbFunc();
    }
}

function register() {
    confirmModal('회원가입에 성공했습니다.', redirecUserInfoPage)
    // confirmModal('회원가입에 성공했습니다.', redirecUserInfoPage()) ← 콜백함수 호출시, 함수명 뒤에 () 붙이지 않게 주의
}

function login() {
    confirmModal('로그인에 성공했습니다.', redirectIndexPage)
}

9) 순수 함수

  • 함수를 정의할 때는 사이트 이펙트를 줄이기 위해, 함수를 ‘컨테이너화’ 해야한다.
  • 그리고 이렇게 함수르 컨테이너화 하는 것을 ‘순수 함수’라고 한다.
// 예시 1 - 순수 함수가 아닌 예
// num1과 num2가 컨테이너화 되지 않아, 사이드 이펙트가 발생할 수 있음
let num1 = 10;
let num2 = 20;

function impurityFunction() {
    return num1 + num2;
}

console.log(impurityFunction(num1, num2));

// 사이드 이펙트 발생
num1 = 30;
console.log(impurityFunction(num1, num2));
// 예시 1 - 순수 함수로 리팩토링 예
// 매개 변수로 정의하여, 사이드이펙트 방지
function impurityFunction(num1, num2) {
    return num1 + num2;
}

console.log(impurityFunction(10, 20));

  • reference type(배열, 객체)을 인자로 받는 경우, 새로운 배열, 객체를 반환하도록 한다.
  • 왜냐하면, reference type은 옮겨 담을 때, 동일한 위치를 참조하기 때문에 사이드 이펙트가 발생할 수 있다.
// 예시 2 - 객체를 인자로 받아 수정 후, 새로운 객체로 리턴하지 않는 경우 발생하는 문제
const obj = { one: 1 };

function changeObj(targetObj) {
    targetObj.one = 100;

    return targetObj;
}

console.log(changeObj(obj)); // { one: 100 }, 예상 결과대로 나옴
console.log(obj); // { one: 100 }, 오류: 값이 같이 변경되어 버림


// 예시 2 - 객체를 인자로 받아 수정 후, 새로운 객체로 리턴하지 않는 경우 발생하는 문제
const obj = { one: 1 };

function changeObj(targetObj) {
    // 스프레드 연산자로 새로운 객체를 리턴
    return { ...targetObj, one: 100 };
}

console.log(changeObj(obj)); // { one: 100 }
console.log(obj); // { one: 1 }

다음에 다루게 될 것

  • 추상화, 에러 다루기

댓글남기기