Arrow Functions

사랑 스럽게도 fat arrow => 라고도 불립니다. 다른 언어에서는 lambda function 이라고도 알려 져 있죠. fat arrow는 다음과 같은 이유료 탄생했습니다.

  1. function을 다 입력하지 않아도 됩니다.
  2. this의 의미를 문법적으로 적절히 해석해 줍니다.
  3. arguments의 의미를 문법적으로 적절히 해석해 줍니다.

함수형 언어라 하는 것들은 함수를 자주 선언하게 마련입니다. JavaScript에서는 function 키워드를 통해 함수를 선언하게 되죠. fat arrow는 이러한 선언을 조금이라도 간략하게 해 줍니다.

var inc = (x) => x + 1;

처음 JavaScript를 배울 때, this 키워드의 개념을 잡는 것이 쉽지 않습니다. 다른 언어에서 클래스를 정의하고 그 내부에서 사용하는 this는 통상 해당 클래스의 자기 자신의 객체를 가리킵니다. 하지만, JavaScript 에서는 호출한 객체가 될 수도 있으며, call, apply built in 함수등을 통해 this가 가리키는 객체를 변경할 수도 있습니다.

다음의 순수한 JavaScript로 정의한 클래스 객체를 예로 들어 보겠습니다.

function Person(age) {
    this.age = age;
    this.increaseAge = function() {
        this.age++; // 여기에서의 this는 항상 Person 객체의 인스턴스 일까요?
    }
}

var person = new Person(1);
// 여기서 person.age는 1 입니다.

setTimeout(person.increaseAge,1000);
// 1초 뒤에 수행한 increaseAge 로 인해 person.age가 2가 될까요?

setTimeout(function() { console.log(person.age); },2000);
// 2초 뒤에 수행한 결과는 1 입니다.

만일, 위의 코드를 브라우저에서 수행하면, increaseAge 함수의 thiswindow 객체를 가리키게 됩니다. 이는 increaseAge를 호출한 객체가 window이기 때문입니다.

이제 arrow function을 사용한 예제 입니다.

function Person(age) {
    this.age = age;
    this.growOld = () => {
        this.age++;
    }
}
var person = new Person(1);
setTimeout(person.growOld,1000);

setTimeout(function() { console.log(person.age); },2000);
// 이제는 2 값으로 출력 합니다.

위와 같이 동작하는 이유는 arrow function 에서 사용한 this는 실제로 arrow function 밖에서 참조한 this이기 때문 입니다. 다음은 위의 코드를 TypeScript로 컴파일한 결과 입니다.

function Person(age) {
    var _this = this;
    this.age = age;
    this.growOld = function () {
        _this.age++;
    };
}
var person = new Person(1);
setTimeout(person.growOld, 1000);

setTimeout(function () { console.log(person.age); }, 2000);

TypeScript로 작성하면 class 키워드를 사용해서 조금더 멋진 코드를 작성할 수 있습니다.

class Person {
    constructor(public age:number) {}
    growOld = () => {
        this.age++;
    }
}
var person = new Person(1);
setTimeout(person.growOld,1000);

setTimeout(function() { console.log(person.age); },2000); // 2

관련 동영상 🌹

Tip: Arrow Function Need

다음과 같이 다른 호출 컨텍스트에서 함수를 호출하고자 한다면 arrow function 대신 function 을 사용해야 합니다.

var growOld = person.growOld;
// Then later someone else calls it:
growOld();

호출 컨텍스를 선언한 객체 자신에서만 유지하고자 할때만, arrow function을 사용합니다.

person.growOld();

growOld 함수를 arrow function으로 정의했다면, growOld 함수 내에서 참조하는 thisperson이 됩니다.

Tip: Arrow Function Danger

만일 정의하는 함수에서의 this의 calling context를 변경하고자 한다면 arrow function 보다는 function으로 함수를 정의해야 합니다. 또한 arrow function 에서는 arguments는 사용할 수 없다.

Tip: Arrow functions with libraries that use this

jQuery를 포함한 여러 라이브러리들 중 jQuery.each와 같은 반복 가능한 함수(interables) 들은 this를 현재의 값으로 설정해서 함수를 호출 합니다. 따라서, 이경우 arrow function을 주의해서 사용해야 합니다.

예를 들어 아래와 같이 코딩을 하면,

let _self = this;
$('li').each(() => {
    console.log(_self);
    console.log(this);
});

아래와 같은 코드를 생성합니다.

var _this = this;
var _self = this;
something.each(function () {
    console.log(_self);
    console.log(_this);
});

this가 함수를 정의한 외부 컨텍스트를 가지게 되는 것이죠.

jQuery를 이용해 개발자들이 원하는 결과를 얻으려면 다음과 같이 작성해야 합니다.

let _self = this;
$('li').each(function() {
    console.log(_self); // the lexically scoped value
    console.log(this); // the library passed value
});

Tip: Arrow functions and inheritance

arrow function을 통해 정의한 member 함수는 사실 상 member 변수 입니다. 다시말하면, 함수형의 변수에 arrow function을 사용하여 anonymous function을 선언 과 동시에 대입을 하는 것 입니다.

다음의 예를 살펴 봅니다.

class Adder {
    constructor(public a: number) {}
    add = (b: number): number => {
        return this.a + b;
    }
}

class ExtendedAdder extends Adder {
    add = (b: number): number => {
        return super.add(b); // 에러 발생
    }
}

위의 코드는 사실상, 자식 클래스(ExtendedAdder) 가 부모 클래스(Adder)의 함수(add)를 overriding 을 한다기 보다는, 부모 클래스의 add 맴버 변수에 새로운 anonymous 함수를 정의해서 대입하는 것이죠.

따라서 위와같이 super.add(b)와 같은 성립하지 않음으로 컴파일 에러가 발생합니다.

super 를 사용하고자 한다면 다음과 같이 member 함수로 선언하면 됩니다.

class Adder {
    constructor(public a: number) {}
    add(b: number): number {
        return this.a + b;
    }
}

class ExtendedAdder extends Adder {
    add(b: number): number {
        return super.add(b);
    }
}

results matching ""

    No results matching ""