화살표 함수 (Arrow Function) 의 선언
화살표 함수는 function 키워드 대신 화살표를 사용하여 보다 간략한 방법으로 함수를 선언할 수 있따.
하지만, 모든 경우 화살표 함수를 사용할 수 있는 것은 아니다. 화살표 함수의 기본 문법은 아래오 같다.
// 매개변수 지정 방법
() => { ... } // 매개변수가 없을 경우
x => { ... } // 매개변수가 한 개인 경우, 소괄호를 생략할 수 있다.
(x, y) => { ... } // 매개변수가 여러 개인 경우, 소괄호를 생략할 수 없다.
// 함수 몸체 지정 방법
x => { return x * x } // single line block
x => x * x // 함수 몸체가 한줄의 구문이라면 중괄호를 생략할 수 있으며 암묵적으로 return된다. 위 표현과 동일하다.
() => { return { a: 1 }; }
() => ({ a: 1 }) // 위 표현과 동일하다. 객체 반환시 소괄호를 사용한다.
() => { // multi line block.
const x = 10;
return x * x;
};
화살표 함수의 호출
화살표 함수는 익명함수로만 사용할 수 있다. 따라서, 화살표 함수를 호출하기 위해서는 함수 표현식 을 사용해야 한다.
var pow = function (x) { return x * x; };
console.log(pow(10)); // 100
//OR
const pow = x => x * x;
console.log(pow(10)); // 100
또는, 콜백 함수로도 사용할 수 있다. 이 경우, 일반적인 함수 표현식보다 간결하다.
var arr = [1, 2, 3];
var pow = arr.map(function (x) { // x는 요소값
return x * x;
});
console.log(pow); // [ 1, 4, 9 ]
//OR
const arr = [1, 2, 3];
const pow = arr.map(x => x * x);
console.log(pow); // [ 1, 4, 9 ]
this
function 키워드로 생성한 일반 함수와 화살표 함수의 가장 큰 차이는 this이다.
일반 함수의 this
자바스크립트의 경우 함수 호출 방식에 의해 this에 바인딩할 어떤 객체가 동적으로 결정된다.
즉, 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정되는 것이 아니고, 함수를 호출할 때 함수가 어떻게 호출되었는지에 따라 this에 바인딩할 객체가 동적으로 결정된다.
콜백 함수 내부의 this는 전역 객체 window를 가리킨다.
function Prefixer(prefix) {
this.prefix = prefix;
}
Prefixer.prototype.prefixArray = function (arr) {
// (A)
return arr.map(function (x) {
return this.prefix + ' ' + x; // (B)
});
};
var pre = new Prefixer('Hi');
console.log(pre.prefixArray(['Lee', 'Kim']));
A 지점에서의 this는 생성자 함수 Prefixer가 생성한 객체, 즉, 생성자 함수의 인스턴스(pre)이다.
B 지점에서 사용한 this는 아마도 생성자 함수 Prefixer가 생성한 객체(pre)일 것이라고 기대했겟지만, B의 this는 전역 객체 window를 가리킨다.
이는 생성자 함수와 객체의 메소드를 제외한 모든 함수 내부의 this는 전역 객체를 가리키기 때문이다.
화살표 함수의 this
화살표 함수는 일반 함수와 달리 선언할 때 this에 바인딩할 객체가 정적으로 결정된다.
화살표 함수의 this는 언제나 상위 스코프의 this를 가리킨다. 이를 Lexical this라 한다.
function Prefixer(prefix) {
this.prefix = prefix;
}
Prefixer.prototype.prefixArray = function (arr) {
// this는 상위 스코프인 prefixArray 메소드 내의 this를 가리킨다.
return arr.map(x => `${this.prefix} ${x}`);
};
const pre = new Prefixer('Hi');
console.log(pre.prefixArray(['Lee', 'Kim']));
화살표 함수는 call, apply, bind 메소드를 사용하여 this를 변경할 수 없다.
화살표 함수를 사용해서는 안되는 경우
화살표 함수는 Lexical this를 지원하므로 콜백 함수로 사용하기 편리하다.
하지만, 화살표 함수를 사용하는 것이 오히려 혼란을 불러오는 경우도 있으므로 주의하자.
메소드
화살표 함수로 메소드를 정의하는 것은 피해야한다.
// Bad
const person = {
name: 'Lee',
sayHi: () => console.log(`Hi ${this.name}`)
};
person.sayHi(); // Hi undefined
메소드로 정의한 화살표 함수 내부의 this는 메소드를 소유한 객체,
즉 메소드를 호출한 객체를 가리키지 않고 상위 컨텍스트인 전역 객체 window를 가리킨다.
따라서, 화살표 함수로 메소드를 정의하는 것은 바람직하지 않다.
이와 같은 경우 메소드를 위한 단축 표기법을 사용하는 것이 좋다.
// Good
const person = {
name: 'Lee',
sayHi() { // === sayHi: function() {
console.log(`Hi ${this.name}`);
}
};
person.sayHi(); // Hi Lee
prototype
화살표 함수로 정의된 메소드를 prototype에 할당하는 경우도 동일한 문제를 발생한다.
// Bad
const person = {
name: 'Lee',
};
Object.prototype.sayHi = () => console.log(`Hi ${this.name}`);
person.sayHi(); // Hi undefined
화살표 함수로 객체의 메소드를 정의했을 때랑 같은 문제가 발생한다. 따라서, prototype 메소드를 할당하는 경우, 일반함수를 사용하자.
// Good
const person = {
name: 'Lee',
};
Object.prototype.sayHi = function() {
console.log(`Hi ${this.name}`);
};
person.sayHi(); // Hi Lee
생성자 함수
생성자 함수는 prototype 프로퍼티를 가지며 prototype 프로퍼티가 가리키는 프로토 타입 객체의 constructor를 사용한다.
하지만 화살표 함수는 prototype 프로퍼티를 가지고 있지 않다. 그래서, 화살표 함수는 생성자 함수로 사용할 수 없다.
addEventListener 함수의 콜백 함수
addEventListener 함수의 콜백 함수를 화살표 함수로 정의하면 this가 상위 컨텍스트인 전역 객체 window를 가리킨다.
따라서 addEventListener 함수의 콜백 함수 내에서 this를 사용하는 경우, function 키워드로 정의한 일반 함수를 사용해야 한다.
일반 함수로 정의된 addEventListener 함수의 콜백 함수 내부의 this는 이벤트 리스너에 바인딩 된 요소(currentTarget)을 가리킨다.
// Bad
var button = document.getElementById('myButton');
button.addEventListener('click', () => {
console.log(this === window); // => true
this.innerHTML = 'Clicked button';
});
// Good
var button = document.getElementById('myButton');
button.addEventListener('click', function() {
console.log(this === button); // => true
this.innerHTML = 'Clicked button';
});
'Javscript' 카테고리의 다른 글
[JS] package.json, package-lock.json 이 뭐에요 ? (feat, ^(caret)와 ~(tilde)) (1) | 2024.01.27 |
---|---|
[Javascript] 인증과 인가, 암호화, jwt (flask, bcrypt) (0) | 2022.02.02 |
[Javascript] 이벤트루프, 동시성, 이벤트 종류 (1/30) (0) | 2022.01.30 |
[Javascript] onclick event(인라인 이벤트, eventlistener, onclick 차이점) (2) | 2022.01.29 |
[Javascript] DOM (문서 객체 모델:Document Object Model) (1/29) (0) | 2022.01.29 |