화살표 함수와 일반 함수가 헷갈려서 정리하고자 작성한다! 화살표 함수란 5가지 개념
만 이해하면 간단하다.
화살표 함수는 익명함수이다. 즉 이름이 없다. 함수 표현식으로 선언 할 경우 익명함수로 선언하게 되는데 화살표 함수도 이와 동일하게 선언하면 된다.
선언 방식은 매우 매우 very very very 간단하다.
const arrowfunc = () => {
}
끝이다. 함수표현식 처럼 변수에 함수를 할당하는것 처럼 선언하는데 = 뒤에 () 매개변수가 들어가고 그 다음 => 이름 처럼 화살표가 들어간다. 그러고 나서 {} 함수 몸체를 선언하면 된다! 여기서 또 2가지를 알아야한다.
// 매개변수가 없을 경우
const arrowfunc = () => {
}
// 매개변수가 하나인 경우
const arrowfunc = arg => {
}
// 매개변수가 두개이상 일 경우
const arrowfunc = (arg1,arg2) => {
}
매개변수가 없을 경우와 두개 이상일 경우는 필히 ()로 선언해야 하며 하나일 경우 생략할 수 있다.
또한 함수에서 바로 리턴을 하고 싶은 경우 {} 함수몸체와 return 키워드를 생략할 수도 있다.
const arrowfunc = arg => arg + arg; // 이런 코드는 return으로 인식함.
일반적인 함수에는 arguments 프로퍼티가 존재한다. 하지만 화살표 함수에는 arguments가 없다.
const func = function() {
console.log(arguments);
}
func(1,2,3,4,5); // [1,2,3,4,5];
const arrowfunc = () => {
console.log(arguments);
}
arrowfunc(1,2,3,4,5); // ReferenceError: arguments is not defined
대신 화살표 함수에서는 args를 이용하면 된다.
const arrowfunc = (...args) => { // ... 전개연산자를 사용해야함.
console.log(args);
}
arrowfunc(1,2,3,4,5); // [1,2,3,4,5];
여기서 arguments와 args의 차이점은 arguments는 배열이 아닌 유사배열이고 args는 배열이다.
일반 함수에는 prototype 프로퍼티가 존재 하지만 화살표 함수에는 없다.
const Func = function() {
}
const arrowfunc = () => {
}
console.dir(Func);
console.dir(arrowfunc);
위 코드를 실행하여 개발자 도구에서 출력했다. 사진으로 보다 싶이 없다.
prototype 프로퍼티가 없다는건 즉 화살표 함수는 생성자 함수로 사용할 수 없다.
일반 함수는 자기 자신만의 this를 가지고 있으며 이 this는 함수 호출 패턴에 따라 달라진다. 하지만 화살표 함수는 말 그대로 this가 없다. 있는것 처럼 보일수는 있지만 그냥 정확히 없다.
화살표 함수에서 this를 만나면 스코프체인에 따라 this를 찾는다.
const a = {
age: '3',
say: () => {
console.log(`내 나이는 ${this.age} 이다.`);
}
}
a.say(); // 내 나이는 undefined 이다.
객체를 선언하고 그 객체의 say 메서드를 호출했다. 당연히 내 나이는 3 이다. 라고 나올거 같았는데 undefined가 나왔다. 일반 함수 같으면 this를 동적으로 결정하기 때문에 자신을 호출한 대상 a객체가 this가 되겠지만 화살표 함수는 this가 없다고 했다. 그냥 얘는 자기 스코프 체인을 따라간다. say에서의 this는 없고 스코프 체인을 따라 전역에서도 찾았는데도 없다. 결국 undefined를 출력한다. 음.. 이걸 보고 알아야 할 점은? 화살표 함수는 객체의 메서드로 사용하지 말자.
function Person(age) {
this.age = age;
}
Person.prototype.myAge = function (a) {
return a.map(function(x) {
return `${x} ${this.age} 입니다.`;
});
}
const jeon = new Person(3);
const ary = jeon.myAge(['내나이는']);
console.log(ary); // ["내 나이는 undefined 입니다."];
음 이건 좀 다른 코드이다. 위 코드는 Person 객체 메서드에서 함수를 다시 리턴했다. 보통 내부함수나 콜백함수는 this가 전역에 바인딩되어 버려서 전혀 엉뚱한 결과가 나올거다. 그럼 어떻게 하지?
function Person(age) {
this.age = age;
}
Person.prototype.myAge = function (a) {
return a.map((function(x) {
return `${x} ${this.age} 입니다.`;
}).bind(this));
}
bind를 사용하여 this를 바인딩 해버리면 된다. 그럼 이걸 할때마다 이렇게 해야할까? 귀찮다. 그냥 화살표 함수를 쓰자!
function Person(age) {
this.age = age;
}
Person.prototype.myAge = function (a) {
return a.map(x => `${x} ${this.age} 입니다`);
}
const jeon = new Person(3);
const ary = jeon.myAge(['내나이는']);
console.log(ary); // ["내 나이는 3 입니다."];
깔끔하다. 화살표 함수는 아까 말했듯 동적으로 결정되지 않고 스코프체인을 탐색한다. myAge 메서드의 리턴값 화살표함수에서 this를 찾는다. 어 this가 없네? 스코프체인을 탐색한다. 자신의 바깥 스코프는 myAge다. myAge에서 this를 찾는다. 어 this가 있네? 그렇다면 myAge에서의 this는? 호출한 대상 jeon 객체다. ["내 나이는 3 입니다."] 내가 원하는 결과가 출력됐다.