[JS] ES6 화살표 함수

Y_Y·2023년 9월 22일
0

JavaScript

목록 보기
4/5

Arrow Function

출처 : MDN

  • this, arguments나 super에 대한 자체 바인딩이 없고, methods로 사용해서는 안됩니다.

  • new.target키워드가 없습니다.

  • 생성자(Constructor)로 사용할 수 없습니다.

  • 일반적으로 스코프를 지정할 때 사용하는 call, apply, bind methods를 이용할 수 없습니다.

  • yield를 화살표 함수 내부에서 사용할 수 없습니다.

Example

const materials = ['Hydrogen', 'Helium', 'Lithium', 'Beryllium'];

console.log(materials.map((material) => material.length));
// Expected output: Array [8, 6, 7, 9]

기본 구문

    (param1, param2, …, paramN) => { statements }
    (param1, param2, …, paramN) => expression
    // 다음과 동일함:  => { return expression; }

    // 매개변수가 하나뿐인 경우 괄호는 선택사항:
    (singleParam) => { statements }
    singleParam => { statements }

    // 매개변수가 없는 함수는 괄호가 필요:
    () => { statements }

상세 구문

    var elements = [
      'Hydrogen',
      'Helium',
      'Lithium',
      'Beryllium'
    ];

    // 이 문장은 배열을 반환함: [8, 6, 7, 9]
    elements.map(function(element) {
      return element.length;
    });

    // 위의 일반적인 함수 표현은 아래 화살표 함수로 쓸 수 있다.
    elements.map((element) => {
      return element.length;
    }); // [8, 6, 7, 9]

    // 파라미터가 하나만 있을 때는 주변 괄호를 생략할 수 있다.
    elements.map(element => {
      return element.length;
    }); // [8, 6, 7, 9]

    // 화살표 함수의 유일한 문장이 'return'일 때 'return'과
    // 중괄호({})를 생략할 수 있다.
    elements.map(element => element.length); // [8, 6, 7, 9]

    // 이 경우 length 속성만 필요하므로 destructuring 매개변수를 사용할 수 있다.
    // 'length'는 우리가 얻고자 하는 속성에 해당하는 반면,
    // lengthFooBArX'는 변경 가능한 변수의 이름일 뿐이므로
    // 원하는 유효한 변수명으로 변경할 수 있다.
    elements.map(({ length: lengthFooBArX }) => lengthFooBArX); // [8, 6, 7, 9]

    // destructuring 파라미터 할당도 아래와 같이 작성할 수 있습니다.
    // 이 예에서 정의한 객체내의 'length'에 값을 지정하지 않은 점에 주목하세요. 대신, "length" 변수의
    // 리터럴 이름은 우리가 해당 객체에서 꺼내오고 싶은 속성이름 자체로 사용됩니다.
    elements.map(({ length }) => length); // [8, 6, 7, 9]

바인딩 되지 않은 this

화살표 함수가 나오기 전까지는, 모든 새로운 함수는, 어떻게 그 함수가 호출되는지에 따라 자신의 this 값을 정의했습니다:
객체 지향 스타일에 어울리지 않음.

function Person() {
  // Person() 생성자는 `this`를 자신의 인스턴스로 정의.
  this.age = 0;

  setInterval(function growUp() {
    // 비엄격 모드에서, growUp() 함수는 `this`를
    // 전역 객체로 정의하고, 이는 Person() 생성자에
    // 정의된 `this`와 다름.
    this.age++;
    consoel.log(this.age) // 1초당 NaN 출력
  }, 1000);
}

var p = new Person();

ECMAScript 3/5 에서는, 이 문제를 this 값을 폐쇄될 수 있는 (비전역) 변수에 할당하여 해결했습니다.

function Person() {
  var that = this; // 비전역 변수에 this 할당
  that.age = 0;

  setInterval(function growUp() {
    // 콜백은  `that` 변수를 참조하고 이것은 값이 기대한 객체이다.
    that.age++;
  }, 1000);
}

화살표 함수는 자신의 this가 없습니다. 대신 화살표 함수를 둘러싸는 *렉시컬 범위(lexical scope)의 this가 사용됩니다; 화살표 함수는 일반 변수 조회 규칙(normal variable lookup rules)을 따릅니다. 때문에 현재 범위에서 존재하지 않는 this를 찾을 때, 화살표 함수는 바로 바깥 범위에서 this를 찾는것으로 검색을 끝내게 됩니다.

따라서 다음 코드에서 setInterval에 전달 된 함수 내부의 this는 setInterval을 포함한 function의 this와 동일한 값을 갖습니다.

  • 렉시컬 범위 : 렉시컬 범위는 함수의 실행 시 범위를 함수 정의 단계의 범위로 참조하는 특성이다.

요약 : 화살표 함수가 나오기 이전에는 새로운 지역변수를 할당하고 this 바인딩했다면 이후 화살표 함수 내 렉시컬 범위에 따라 this를 찾아 간단하게 지정.

function Person() {
  this.age = 0;

  setInterval(() => {
    this.age++; // |this|는 Person 객체를 참조
    console.log(this.age); // 1, 2, 3, 4 , ...N
  }, 1000);
}

var p = new Person();

setTimeout(() => {
  console.log('10초 뒤 age : ', p.age); // 10초 뒤 age : 9
}, 10000); // 10000밀리초(10초) 뒤에 실행

call 또는 apply를 통한 피호출

화살표 함수에서는 this 가 바인딩되지 않았기 때문에, call() 또는 apply() 메서드는 인자만 전달 할 수 있습니다. this는 무시됩니다.

  • 화살표 함수 f는 자체적으로 this를 바인딩하지 않고, 외부 스코프에서 this 값을 상속받습니다. 즉, f 내부에서의 this는 addThruCall 메서드가 속한 adder 객체를 가리킵니다.
  • 따라서 f.call(b, a)를 호출해도 f 내부의 this는 adder 객체를 가리키므로, this.base는 여전히 1로 설정되며, 결과적으로 1 + 1이 계산되어 2가 반환됩니다.

요약 : 화살표 함수는 자체적으로 this를 바인딩하지 않고 외부 스코프의 this 값을 상속받기 때문에 f 내부에서의 this는 add 메서드와 addThruCall 메서드가 속한 adder 객체를 가리키게 됩니다.

var adder = {
  base: 1,

  add: function (a) {
    var f = (v) => v + this.base;
    return f(a);
  },

  addThruCall: function (a) {
    var f = (v) => v + this.base; // 1 + 1
    // var f = (v) => v + this.base + ' v ' + v + ' this.base ' + this.base; 2 + 1
    var b = {
      base: 2,
    };

    return f.call(b, a);
  },
};

console.log(adder.add(1)); // 이는 2가 콘솔에 출력될 것임
console.log(adder.addThruCall(1)); // 이도 2가 콘솔에 출력될 것임

바인딩 되지 않은 arguments

화살표 함수는 arguments 객체를 바인드 하지 않습니다. 때문에, arguments는 그저 둘러싸는 범위(scope) 내 이름에 대한 참조입니다.

var arguments = [1, 2, 3];
var arr = () => arguments[0];

console.log(arr()); // 1

function foo(n) {
  var f = () => arguments[0] + n; // foo's implicit arguments binding. arguments[0] is n
  console.log('argu : ', arguments[0]);
  console.log('n : ', n);
  return f();
}

console.log(foo(1)); // 2 = argu : 1 , n : 1
console.log(foo(2)); // 4 = argu : 2 , n : 2

기본 사용법

//  empty 화살표 함수는 undefined를 반환
let empty = () => {};

(() => "foobar")();
// "foobar" 반환
// (this is an Immediately Invoked Function Expression

var simple = (a) => (a > 15 ? 15 : a);
simple(16); // 15
simple(10); // 10

let max = (a, b) => (a > b ? a : b);

// Easy array filtering, mapping, ...

var arr = [5, 6, 13, 0, 1, 18, 23];

var sum = arr.reduce((a, b) => a + b);
// 66

var even = arr.filter((v) => v % 2 == 0);
// [6, 0, 18]

var double = arr.map((v) => v * 2);
// [10, 12, 26, 0, 2, 36, 46]

// 더 간결한 promise 체인
promise
  .then((a) => {
    // ...
  })
  .then((b) => {
    // ...
  });

// 매개변수가 없는 경우에도 더 읽기 쉬움
setTimeout(() => {
  console.log("I happen sooner");
  setTimeout(() => {
    // deeper code
    console.log("I happen later");
  }, 1);
}, 1);
profile
남을 위해(나를 위해) 글을 쓰는 Velog

0개의 댓글