Advantages and Pitfalls of Arrow Functions
There are big differences between arrow functions and classic function expressions.
medium.com
해당 게시물을 참고해서 번역했습니다.
이 글에 들어가기 앞서 먼저 알아두면 좋은 개념을 설명 합니다. 아시는 분은 넘어가도 됩니다.
context : 함수를 호출한 object
scope : 현재 실행되는 context로 여기서 context는 값과 표현식이 표현되거나 참조 될 수 있는 것을 의미 한다.
lexical scope(stactic scope): 함수나 변수의 scope를 호출된 곳이 아닌 정의 된 곳을 기준으로 정함.
dynamic scope : 함수나 변수의 scope를 호출된 라인을 기준으로 정함.
this : 함수 내에서 함수를 호출한 context를 뜻한다.
화살표 함수에서는 자신을 감싼 stactic scope, 전역 코드에서는 global object를 가리킨다
bind :
ECMAScript5에서 도입되었습니다. f.bind(someObject)를 호출하면 f와 같은 본문(코드)과 범위를 가졌지만 this는 원본 함수를 가진 새로운 함수를 생성합니다. 새 함수의 this는 호출 방식과 상관없이 영구적으로bind()의 첫 번째 매개변수로 고정됩니다.
일반 함수와 화살표 함수 사이에는 큰 차이가 있습니다. 어떤 상황에서는 훨씬 효과적이지만 어떤 때에는 그렇지 못합니다.
Javascript 화살표 함수는 함수를 작성하는 더욱 효과적인 방법으로 ES2015에서 도입되었습니다. 아래 코드 예시에서 foo와 bar는 같은 기능을 합니다.
let foo = function() {
console.log('BAZ')
}
let bar = () => {
console.log('BAZ')
}
foo() // BAZ
bar() // BAZ
하지만 화살표 함수는 단순히 function 으로 표현되는 함수의 syntactic sugar(같은 기능을 하지만 더 쉽게 작성할 수 있는 새로운 문법)가 아닙니다. 여기엔 반드시 알아야하는 큰 차이가 있습니다. 이 차이는 화살표 함수를 더 멋지게 만들지만, 제대로 알고 쓰지 않으면 문제가 생길 수 있습니다. 이 경우 화살표 함수로 해결할 수 없으므로 function 함수 식을 사용해야 합니다.
화살표 함수와 this
function 함수 표현에서 this 키워드는 함수가 호출된 context에 따라 바인드 됩니다. 반면 화살표 함수는 lexical scope에서 이 값을 사용합니다. 이 차이로 다른 동작을 하게 됩니다. context는 어떻게 호출되었는지가 중요하고 scope는 어떻게 정의되었는지가 중요합니다.
context에 관한 예시입니다. 함수에 의해 method가 정의된 객체를 봐주세요.
let obj = {
myVar: 'foo',
myFunc: function() {
console.log(this.myVar)
}
}obj.myFunc() // foo
obj는 myFunc를 호출합니다. obj는 myFunc의 context입니다. 그래서 myFunc에서 this의 값이 obj에 바인딩됩니다. context는 어떻게 호출되냐에 따라 다르게 정의될 수 있습니다. 예를 들어, constructor가 new 라는 keyword와 함께 호출될 때 this는 생성된 object를 일컫습니다. context에 대한 자세한 사항은
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/this 더 보실 수 있습니다.
만약 this가 context에 바인드되었다면 (i.e. 함수를 호출한 obect에 바인딩) 이는 callback 함수 사용 시 예상과 다른 결과를 보입니다.
callback 함수에서 어떻게 동작하는지 보기 위해 setTimeout을 object.myFunc에 추가해보겠습니다.
let obj = {
myVar: 'foo',
myFunc: function() {
console.log(this.myVar)
setTimeout(function() {
console.log(this.myVar)
}, 1000)
}
}obj.myFunc() // foo ... then... undefined
myFunc에서 this의 값은 obj를 가리킵니다. 즉 myFunc.myVar의 결과를 보면 'foo'가 출력됩니다. 그러나 두번째 함수는 setTimeout에 의해 호출됩니다. 여기 context는 다릅니다. 여기서 context는 Node의 Timeout object 또는 브라우저의 window ojbect를 뜻합니다. 그런 이유로 우리는 this를 obj로 생각했지만 결과를 보면 우리가 의도한 this의 값은 undefined로 출력됩니다.
우리가 의도한대로 값을 얻기 위해선 몇가지 방법을 사용해야합니다. 첫번째 방법은 this를 대게 self나 that이라는 이름으로 명명하는 변수에 할당하는 방법입니다. 해당 변수는 callback 함수의 lexical scope안에 있습니다. 이는 callback 함수가 scope안에서 정의되었기 때문에 위에서 만들었던 변수에 접근할 수 있음을 의미합니다.
let obj = {
myVar: 'foo',
myFunc: function() {
let self = this console.log(this.myVar)
setTimeout(function() {
console.log(self.myVar)
}, 1000)
}
}obj.myFunc() // foo ... then... foo
우리는 딱봐도 화살표 함수가 callback 함수에 적합하다는 것을 알 수 있습니다. 그러나 우리가 화살표 함수를 object method로 사용하게 된다면 어떻게 될까요 ?
let obj = {
myVar: 'foo',
myFunc: () => {
console.log(this.myVar)
}
}obj.myFunc() // undefined
위와 같은 코드를 보면 this가 obj를 말한다고 생각할 수 있습니다. 하지만 여기서 this는 화살표 함수를 호출한 obect에 바인딩하지 않습니다. 화살표 함수는 this의 값을 자기 자신이 정의된 scope의 값을 사용합니다. 여기서는 global object를 일컫습니다. 그래서 화살표 함수는 object method로 사용될 수 없습니다.
function 함수는 object method로 적합하고, 화살표 함수는 callback 함수나 map과 같은 method에 가장 적합합니다.
scope에 대해 아래 링크에서 더 읽어보실 수 있습니다.
https://developer.mozilla.org/en-US/docs/Web/CSS/:scope
기본적으로 화살표 함수는 자신의 scope에서 this 값과 다른 값을 바인딩할 수 없습니다. 따라서 bind(), call(), apply() method는 여기의 값에 영향을 주지 않습니다.
생성자(constructor)
화살표 함수가 object에서 제대로 작동하지 않게하는 다른 방법이 있습니다. 이 것들은 constructor가 될 수 없습니다. function 함수 표현식은 새로운 obect를 생성할때 다음과 같이 사용됩니다.
let Person = function(name, height) {
this.name = name
this.height = height
}Person.prototype.hello = function() {
console.log('Hi, my name is ' + this.name)
}let alice = new Person('Alice', 1.7)
alice.hello() // Hi, my name is Alice
하지만 화살표 함수는 prototype이라는 property를 가지고 있지 않아서 new와 같이 사용될 수 없습니다.
arguments 바인딩
화살표 함수가 this를 바인딩하지 못하며 단지 자신의 scope의 this 값을 사용한다는 것을 보았다. 화살표 함수는 또한 argument object를 바인딩하지 못한다. function 함수 표현으로는 다음과 같이 할 수 있다.
let sum = function() {
// arguments is available return args.reduce((a, b) => a + b, 0)
let args = Array.from(arguments)
}
sum(1, 2, 3) // 6
화살표 함수는 arguments object가 없다. 하지만 나머지 연산자를 사용해서 같은 기능을 할 수 있다. 코드는 다음과 같다.
let sum4 = (...args) => {
return args.reduce((a, b) => a + b, 0)
}sum(1, 2, 3) // 6
암묵적으로 값을 반환
우리는 위에서 함수를 화살표 함수로 더욱 간결하게 선언할 수 있었습니다. 이 간결한 형식을 사용하면 block에 코드를 감싸지 않아도 됩니다. 함수를 정의하면 화살표 함수가 값을 반환해주기 때문이죠!
let sum = (...args) => args.reduce((a, b) => a + b, 0)
또한 개체 리터럴을 괄호로 묶어서 반환할 수 있습니다.
let getObj = () => ({ foo: 'hello', bar: 'world' })
이 간결한 문법은 화살표 함수를 작고 가독성이 좋은 callback 함수를 정의하는 데에 탁월하게 만듭니다.
요약
화살표 함수는 기존 function 함수 표현과 꽤 다릅니다. 화살표 함수는 callback 함수와 같이 잘 작동하게 하는 몇가지 탁월한 property가 있습니다. 하지만 object methods나 생성자로 쓰이기엔 적절하지 못합니다. 여기엔 몇가지 차이가 존재합니다. 예를들어 화살표 함수는 generators가 될 수 없습니다. 아래 MDN 문서에서 더 자세하게 보시길 바랍니다!
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
'Front-End > JavaScript' 카테고리의 다른 글
값의 재할당 (0) | 2022.04.14 |
---|---|
DOM (0) | 2022.03.23 |
화살표 함수 (0) | 2022.03.23 |
함수 호이스팅(Hoisting) (0) | 2022.03.23 |
콘솔을 통해 값 입력 받기 (0) | 2022.03.23 |