2024.05.17 4차 스터디
오늘의 스터디 주제는? 화살표 함수!
지난 스터디 기록과 이어지는 기록이다. 지난번엔 함수 선언문과 표현식이였다면 이번에는 표현식의 활용버전인 화살표 함수에 대해 알아보고자 한다! 화살표 함수 사용시 주의점이 복잡하고 어려워서 이틀에 걸쳐 작성한 기록이다!
말그대로 화살표를 쓰는 함수라는 뜻이며, 간단한 덧셈을 하는 함수 표현식을 먼저 살펴보자.
함수 표현식
const add = function(a, b) {
return a + b;
};
console.log(add(2, 3)); // 5
add라는 변수에 a와 b라는 매개변수를 더한 값을 반환하는 함수를 할당해보았다.
이제 이 함수를 화살표 함수 표현식으로 바꾸면 아래와 같다.
화살표 함수
const add = (a, b) => {
return a + b;
};
console.log(add(2, 3)); // 5
function이 생략 되고 => 화살표가 생긴 것을 볼 수 있습니다.
이처럼 매개변수 부분이 앞으로 오고 function 단어가 화살표=>로 바뀌어 매개변수 뒤에 위치하는 형태의 함수를 화살표 함수라고 부릅니다. 즉, 매개변수, 화살표 =>, 반환하는 값 순서의 형태를 지니게 됩니다.
화살표 함수를 보다 더 짦게 표현한 것을 짧은 화살표 함수라고 합니다. 위에서 만든 화살표 함수를 짧은 화살표 함수로 만들어보자.
화살표 함수
const add = (a, b) => {
return a + b;
};
console.log(add(2, 3)); // 5
짧은 화살표 함수
const add = (a, b) => a + b;
console.log(add(2, 3)); // 5
화살표 뒤의 중괄호와 리턴이 생략되어 더 짧아진 모습을 볼 수 있습니다.
짧은 화살표 함수는 한 가지 목적을 수행하고 그 목적에 집중하는 단일 함수입니다. 즉, 간단하고 한 가지 일만 수행하는 함수에만 짧은 화살표 함수로 형태를 바꿀 수 있습니다.
const double = x => x * 2;
이 함수는 매개변수 x를 받아서 그 값을 두 배로 만드는 일만 수행합니다. 따라서 짧은 화살표 함수 형태로 사용이 가능합니다.
const double = (arr) => {
// 변수에 함수 할당
const result = arr.map(x => x * 2);
// 결과를 반환
return result;
};
위의 함수는 arr배열을 받아서 각 요소를 두 배로 만드는 작업을 하고, 그 결과를 반환하는 일을 수행합니다. 따라서 이 함수는 여러 작업을 포함하고 있기 때문에 짧은 화살표 함수 형태로 생략이 불가능 합니다.
짧은 화살표 함수는 매개변수의 갯수에 따라 형태가 바뀌게 됩니다.
const add = (a, b) => a + b;
중괄호와 return 키워드를 생략할 수 있습니다.
const square = x => x * x;
매개변수가 하나인 경우 매개변수를 감싸는 괄호를 생략할 수 있습니다.
const sayHello = () => 'Hello';
매개변수가 없는 경우 빈 괄호를 사용합니다.
일반 함수는 호출될 때 this가 결정됩니다. 일반 함수 내에서 this는 함수가 어떻게 호출되었는지에 따라 다릅니다. 전역 컨텍스트에서 정의된 함수는 기본적으로 전역 객체(window 또는 global)를 가리킵니다. 또한 함수가 단순히 호출될 때도 전역 객체를 가리킵니다.
전역 컨텍스트란?
전역 컨텍스트(Global Context)는 자바스크립트 코드가 실행될 때 가장 바깥쪽에 있는 기본 환경입니다. 즉, 모든 코드가 실행되기 시작하는 기본적인 공간이라고 생각하면 됩니다.
또한 객체의 메서드로 정의된 함수에서의 this는 그 메서드를 호출한 객체를 가리킵니다.
객체의 메서드로 정의된 일반 함수
const obj = {
name: "John",
greet: function() {
console.log("Hello, " + this.name);
}
};
obj.greet(); // 출력: Hello, John
greet 메서드는 일반 함수입니다. obj.greet()를 호출하면, this는 메서드를 호출한 객체인 obj를 가리킵니다.
따라서 this.name은 "John"을 참조하여 "Hello, John"이 출력됩니다.
화살표 함수는 자신만의 this 바인딩이 없습니다. 대신, 화살표 함수가 정의된 위치의 상위 스코프의 this를 상속받아 사용합니다.
쉽게 말해, 화살표 함수 내부의 this는 화살표 함수가 작성된 위치에서 this가 무엇이었는지를 그대로 따라갑니다.
상위 스코프란?
상위 스코프는 함수가 정의된 위치를 둘러싸고 있는 외부 환경을 말합니다.
예를 들어, 함수가 객체의 메서드로 정의되었다면, 그 함수의 상위 스코프는 그 객체입니다.
아래 코드에서 greetArrow는 화살표 함수입니다.
const obj = {
name: "John",
greetArrow: () => {
console.log("Hello, " + this.name); // this는 상위 스코프의 this를 가리킴
}
};
obj.greetArrow(); // "Hello, undefined"
greetArrow 화살표 함수가 obj 객체의 메서드로 정의되어 있지만 obj 객체안에는 this가 정의되어 있지 않습니다. 따라서 this는 상위 스코프의 전역 컨텍스트의 객체(window 또는 global)를 가리키는 것 입니다.
전역 객체에는 name 속성이 없으므로 this.name은 undefined입니다.
두 함수를 모두 사용하는 코드를 함께 보겠습니다.
const obj = {
name: "John",
greet: function() {
const innerGreet = () => {
console.log("Hello, " + this.name);
};
innerGreet();
}
};
obj.greet(); // "Hello, John"
상위 스코프 greet함수의 this 정의
obj.greet()를 호출하면 일반 함수인 greet가 this 를 정의합니다.
obj.greet()를 호출 시, greet 안에 있는 this는 호출을 한 객체인 obj를 가리킵니다.
화살표 함수 innerGreet는 일반 함수 greet 내부에 정의된 화살표 함수입니다. 따라서 innerGreet의 상위 스코프는 greet 함수입니다.
화살표 함수가 상위 스코프 greet함수의 this 사용
innerGreet가 호출될 때, this는 상위 스코프인 greet의 this를 그대로 사용합니다.
greet의 this는 obj를 가리키므로, innerGreet의 this도 obj를 가리킵니다.
따라서 this.name은 "John"을 가리키며, "Hello, John"이 출력됩니다.
이처럼 화살표 함수는 자신이 정의된 위치의 상위 스코프에서 this를 상속받아 사용합니다. 이로 인해 화살표 함수는 특히 콜백 함수나 비동기 함수 내에서 유용하게 사용됩니다.
생성자 함수란 ?
객체를 생성할 때 사용되는 특수한 함수입니다. new 키워드를 사용하여 호출되며, 새로운 객체를 반환합니다. 또한 생성자 함수는 일반적으로 첫 글자를 대문자로 시작하는 이름을 가집니다.
즉, 화살표 함수는 new 키워드와 함께 사용할 수 없다는 의미입니다. 화살표 함수는 prototype 속성을 가지지 않으며, 생성자 함수로 사용할 때 필요한 내부 메커니즘을 지원하지 않습니다.
일반 함수
function RegularFunction() {
this.value = 42;
}
일반 생성자 함수
const instance = new RegularFunction();
console.log(instance.value); // 42
화살표 함수
const ArrowFunction = () => {
this.value = 42;
};
화살표 생성자 함수
const instance2 = new ArrowFunction(); // TypeError: ArrowFunction is not a constructor
화살표 함수는 설계 시에 일반 함수에서 제공하는 일부 특수 기능들을 제공하지 않도록 설계되었습니다.
화살표 함수는 주로 콜백 함수나 간단한 함수 표현에 초점을 맞추고 있으며, 클래스나 객체 지향 프로그래밍에서 사용하는 생성자 함수 역할보다는 더 간단하고 짧은 코드 작성을 목적으로 합니다.
arguments 객체란?
함수 내부에서 사용할 수 있는 특별한 객체입니다. 이 객체는 함수가 호출될 때 전달된 모든 인수를 포함합니다. 배열처럼 생겼지만 실제 배열은 아닙니다. 그러나 인덱스를 사용해 접근할 수 있습니다.
function regularFunction(a, b) {
console.log(arguments);
console.log(arguments[0]);
console.log(arguments[1]);
}
regularFunction(1, 2);
// console.log 결과
// arguments > [Arguments] { '0': 1, '1': 2 }
// arguments[0] > 1
// arguments[1] > 2
regularFunction 함수는 arguments 객체를 통해 전달된 인수 1과 2를 참조합니다.
화살표 함수는 arguments 객체를 가지지 않습니다. 대신, 화살표 함수는 화살표 함수가 정의된 위치의 상위 함수의 arguments 객체를 사용합니다.
function outerFunction() {
return () => {
console.log(arguments);
};
}
const arrowFunction = outerFunction(1, 2, 3);
arrowFunction();
// console.log(arguments) 결과
// [Arguments] { '0': 1, '1': 2, '2': 3 }
outerFunction 함수는 호출될 때 1, 2, 3을 받습니다.
outerFunction 안에 있는 화살표 함수는 자신의 arguments 객체가 없기 때문에, 상위 함수인 outerFunction 함수의 arguments 객체(호출 시 전달 된 인수 1, 2, 3)를 참조합니다.
그래서 arrowFunction을 호출하면 outerFunction의 arguments 객체가 출력됩니다.
일반 함수는 자기 자신만의 arguments 객체를 가집니다.
function regularFunction() {
const innerFunction = function() {
console.log(arguments); // innerFunction의 arguments 객체
};
innerFunction(4, 5, 6);
}
regularFunction(1, 2, 3);
// 출력: [Arguments] { '0': 4, '1': 5, '2': 6 }
innerFunction은 호출될 때 전달된 4, 5, 6을 자신의 arguments로 가집니다.
화살표 함수는 자기 자신만의 arguments 객체가 없습니다.
function regularFunction() {
const innerFunction = () => {
console.log(arguments); // regularFunction의 arguments 객체
};
innerFunction(4, 5, 6); // 전달된 인수는 무시됨
}
regularFunction(1, 2, 3);
// 출력: [Arguments] { '0': 1, '1': 2, '2': 3 }
innerFunction은 화살표 함수라서 자신의 arguments가 없기 때문에 화살표 함수가 정의된 상위 함수의 arguments 객체를 사용합니다.
즉, regularFunction의 arguments 객체를 참조하여 regularFunction의 arguments는 1, 2, 3입니다.