본문 바로가기

Javascript

JavaScript - 함수, 화살표 함수와 기존 함수 (Function, Arrow Function and Classic Function)

자바스크립트의 ES6에서 추가된 문법 중 화살표 함수가 있다. 화살표 함수 (arrow function) 란 화살표로 인수를 전달하는 방식으로 함수를 선언하는 것을 말하는데, 기존의 방식의 함수 선언을 대체할 수 있지만, 화살표 함수에 없는 몇 가지가 있다. 이를 다뤄보려고 한다. 함수에 대한 내용은 아래 더보기를 누르면 나온다.

 

더보기

함수란 인수들을 넣었을 때 (또는 넣지 않았을 때), 어떠한 특정 작업들을 처리하는 코드의 모음이다. 어떠한 값들을 반환할 수도 있고 (return), 또는 반환하지 않을 수도 있으며 (void function), 인수 (arguments) 들을 넣을 수도, 넣지 않을 수도 있다. 함수는 코드의 재사용성을 높인다. 가령 사람이 입장할 때마다 그 사람에게 'Hello ~~~" 라고 말해주고 싶다고 하자. 그리고 사람이 5명 입장했다고 하자. 일반적인 방법으론 아래와 같이 할 수 있을 것이다.

 

const person1 = 'Beom Seok';
const person2 = 'Ben';
const person3 = 'Kang';

console.log(`Hello, ${person1}.`);
console.log(`Hello, ${person2}.`);
console.log(`Hello, ${person3}.`);

 

결과

 

PS C:\Users\bumsu\nodejs-projects\노드js교과서> node hello
Hello, Beom Seok.
Hello, Ben.      
Hello, Kang. 

 

그러나 딱봐도 이는 아주 비효율적이다. 예컨대, 사람이 100명이 들어온다면, 아니면 1000명이 들어온다면, 이를 다 일일이 코드로 적을 수 있겠는가? 또한, "Good bye, ~~~"와 같은 말을 해주고 싶은 상황이라면?

 

이러한 반복된 코드의 사용은 유지보수에 어려움을 준다. 예컨대 해주고 싶은 말이 Hello가 아닌 Hi로 바뀌었다면, 또는 한국인에게 안녕하세요라고 말해주고 싶다면, 관련된 코드를 일일이 다 찾아가 바꿔야할 것이다. 함수의 사용은 이러한 점을 방지해주고 코드의 재사용성을 높인다. 함수 sayHello를 다음과 같이 선언해주자.

 

const person1 = 'Beom Seok';
const person2 = 'Ben';
const person3 = 'Kang';

function sayHello(person) {
    console.log(`Hello, ${person}.`);
}
function sayGoodBye(person) {
    console.log(`Good Bye, ${person}`);
}

sayHello(person1);
sayHello(person2);
sayHello(person3);
sayGoodBye(person1);

 

결과

 

PS C:\Users\bumsu\nodejs-projects\노드js교과서> node hello
Hello, Beom Seok.
Hello, Ben.      
Hello, Kang.     
Good Bye, Beom Seok

 

코드의 재사용성이 훨씬 높아졌다. 만약 처리해야하는 작업이 반복적이고 더 복잡할 수록, 함수를 사용하여 처리하는 것이 가독성과 유지보수에 훨씬 더 큰 이점을 가져다 줄 것이다.

 

이제 화살표 함수의 사용을 보자. 화살표 함수는 다음과 같이 선언한다.

 

const person1 = 'Beom Seok';
const person2 = 'Ben';
const person3 = 'Kang';

const sayHello = (person) => {
    console.log(`Hello, ${person}`);
};

sayHello(person1);

 

결과

 

PS C:\Users\bumsu\nodejs-projects\노드js교과서> node hello
Hello, Beom Seok

 

인수가 하나라면 소괄호 내에 인수를 전해주지 않아도 된다. 다만 인수가 없다면 소괄호를 무조건 씌워주어야 한다.

 

const sayHello = person => {
    console.log(`Hello, ${person}`);
};

 

작업이 하나라면 중괄호로 묶어주지 않아도 된다.

 

const sayHello = person => console.log(`Hello, ${person}`);

 

반환값은 기존의 function과 같이 return으로 반환해준다.

 

const add = (x, y) => {
    return x + y;
}

 

반환 값이 하나라면, 그리고 처리해야할 다른 작업들이 없다면, 다음과 같이 쓸 수도 있다.

 

const add = (x, y) => x + y;

 

만약 반환할 값이 객체 (중괄호로 묶인) 라면, 중괄호를 바로 쓸 때 함수의 작업 처리로 알아들어 오류가 날 것이다. 따라서 이 경우 소괄호로 묶어주도록 한다. 반환 값은 언제나 소괄호로 묶을 수 있으며, 가독성을 위해 일부러 소괄호로 묶어주기도 한다.

 

const personProps = (name, age) => ({
    name,
    age
}); // return {name: name, age: age};

 

그렇다면 이제 화살표 함수와 기존 함수의 차이점을 알아보자.

 

arguments 속성

 

기존 함수의 속성 중에는 기본적으로 arguments라는 접근할 수 있는 속성이 있다. 그러나 화살표 함수는 이를 지원하지 않는다. 예를 들어,

 

function myFunc() {
    console.log(arguments);
}

myFunc(1,2,3);

 

위와 같은 코드를 실행하면

 

PS C:\Users\bumsu\nodejs-projects\노드js교과서> node hello
[Arguments] { '0': 1, '1': 2, '2': 3 }

 

위와 같은 결과가 나온다. 보면 '0'이라는 속성에 첫 번째 인수가, '1'이라는 속성에 두 번째 인수가 들어가는 등 배열과 유사한 형태를 가진 객체가 출력되는 것을 볼 수 있다. 이것을 유사배열이 (array-like object) 라고 하는데, 배열은 아니지만 배열과 같은 형식으로 사용할 수 있는 객체를 의미한다.

 

그렇다면 화살표 함수는 어떨까? 아래와 같이 실행을 하면 에러가 발생한다.

 

const myFunc2 = () => {
    console.log(arguments);
};

myFunc2(1,2,3);

 

그렇다면 이를 해결하기 위해선 어떻게 하면 될까? 가장 쉬운 방법은 당연히 이러한 현상이 생기지 않도록 넣을 인수를 확실히 정하는 것이지만, 그렇지 않을때도 있다. 그 경우 레스트 (Rest) 연산자를 사용하여 해결할 수 있다.

 

const myFunc2 = (...args) => {
    console.log(args);
};

myFunc2(1,2,3);

 

결과

 

PS C:\Users\bumsu\nodejs-projects\노드js교과서> node hello
[ 1, 2, 3 ]

 

이러한 배열의 형태로 들어오게 된다.

 

함수의 이름

기존 함수는 이름을 function 함수이름() {} 와 같은 방식으로 함수의 이름을 선언할 수 있었다. 그러나 화살표 함수는 이게 불가능하다. 따라서 어떠한 변수에 담아주어야 한다.

 

function myFunc () {
    console.log('hello')
}

const myFunc2 = function () {
    console.log('world')
}

const myFunc3 = () => {
    console.log('!')
}

myFunc();
myFunc2();
myFunc3();

 

즉 화살표 함수는 언제나 익명함수이지만 기존의 함수는 기명함수가 될 수도, 익명함수가 될 수도 있다.

 

this

화살표 함수에는 this가 없다. 예를 들어, 객체에 다음과 같이 함수를 작성해주자.

 

const myObj = {
    name: 'Beom Seok',
    sayHello: function () {
        console.log(`Hello, ${this.name}.`);
    }
};

myObj.sayHello();

 

결과

 

PS C:\Users\bumsu\nodejs-projects\노드js교과서> node hello   
Hello, Beom Seok.

 

그러나 아래와 같이 화살표 함수에서 this를 사용하려 하면 이를 조회하지 못한다.

 

const myObj = {
    name: 'Beom Seok',
    sayHello: () => {
        console.log(`Hello, ${this.name}.`);
    }
};

myObj.sayHello();

 

결과

 

PS C:\Users\bumsu\nodejs-projects\노드js교과서> node hello   
Hello, undefined.

 

이는 기존 함수와 화살표 함수의 차이 때문이다. 기존 함수는 함수의 선언 때 this에 바인딩할 객체가 정적으로 결정되지 않고 함수를 호출할 때, 함수가 어떻게 호출되었는가에 따라 this에 바인딩할 객체가 동적으로 결정된다.

 

화살표 함수는 이와 달리 this에 바인딩할 객체가 정적으로 결정된다. 즉 화살표 함수의 this는 언제나 상위 스코프의 this를 가리킨다. 위 예제의 경우엔 메소드로 정의한 화살표 함수 내부의 this는 메소드를 소유한 객체, 즉 메소드를 호출한 객체가 아닌 상위 컨텍스트인 전역 객체 window를 가리킨다. 따라서 화살표 함수로 메소드를 정의하는 것은 바람직 하지 않다. 이 경우, 아래와 같이 ES6의 축약 메서드 표현을 사용하는 것이 좋다.

 

const myObj = {
    name: 'Beom Seok',
    sayHello () {
        console.log(`Hello, ${this.name}.`);
    }
};

myObj.sayHello();

 

이 외에도 프로토타입에 할당할 경우, 화살표 함수를 생성자 함수로 사용하는 경우, addEventlistner 등의 콜백 함수를 화살표 함수로 정의한 후 this를 불러오는 경우 등에서 문제가 발생할 수 있다. 가장 쉬운 것은 일반적인 함수는 화살표 함수로 정의해주되, 객체 내 함수는 기존 함수 방식으로 정의해주는 것이다.

 

출처

https://www.youtube.com/watch?v=4zjKltnIBug

https://webcoding.tistory.com/entry/JavaSciprt-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-arguments-%EC%9C%A0%EC%82%AC%EB%B0%B0%EC%97%B4%EC%9D%98-%EC%9D%B4%EC%9A%A9

https://jeong-pro.tistory.com/117

https://poiemaweb.com/es6-arrow-function