[JS] 화살표 함수와 Function

gong_ryong·2024년 7월 2일
0

JS Function과 Arrow function

JavaScript (JS)에는 함수를 정의하는 다양한 방식이 있습니다. ES6 이후로 등장한 화살표 함수(arrow function)는 그 전의 function 키워드로 정의하는 방식과는 몇 가지 중요한 차이점을 지니고 있습니다.

1.function 사용법

ES6 이전에는 함수를 정의하기 위해 function 키워드를 사용했습니다. function 키워드로 생성한 함수는 인스턴스를 생성하며 내부에 Function.prototype을 빈 객체로 생성합니다.

function foo1() {
  console.log(arguments);
}

const foo2 = () => {
  console.log(arguments);
};

console.log(foo1.prototype);
// {constructor: ƒ}
console.log(foo2.prototype);
// undefined

또한 function을 생성자 함수로 사용해 새로운 객체를 생성할 수도 있습니다. 이 경우 호출 시 앞에 new 를 붙이지 않으면 일반 함수로 작동합니다.

function Person(name) {
  this.name = name;

  this.sayHello = function () {
    console.log(`${this.name} says 'Hello World!'`);
  };
}

const person1 = new Person("AA");
const person2 = new Person("Ben Brode");
const person3 = Person("CC");

person1.sayHello(); // AA says 'Hello World!'
person2.sayHello(); // Ben Brode says 'Hello World!'
person3.sayHello(); // Uncaught TypeError TypeError: Cannot read properties of undefined (reading 'sayHello')

VSCode에서는 위와 같은 suggestion이 뜹니다. Quick Fix를 통해 친절하게 ES6부터 등장한 Class 생성자로 변환할 수 있습니다.

class Person {
    constructor(name) {
        this.name = name;

        this.sayHello = function () {
            console.log(`${this.name} says 'Hello World!'`);
        };
    }
}

일반 함수의 this는 함수 호출 위치에 따라 달라집니다.

var foo = function () {
  console.dir(this);
};

// 1. 함수 호출
foo(); // window
// window.foo();

// 2. 메소드 호출
var obj = { foo: foo };
obj.foo(); // obj

// 3. 생성자 함수 호출
var instance = new foo(); // instance

// 4. apply/call/bind 호출
var bar = { name: 'bar' };
foo.call(bar);   // bar
foo.apply(bar);  // bar
foo.bind(bar)(); // bar

이에 따라 콜백 함수에서 this가 의도치 않게 바인딩될 수도 있습니다.

const obj1 = {
    name: 'ObjectWithoutCalloutFunction',
    showName: function() {
      console.log(this.name);
    }
  };
  
obj1.showName(); // 'ObjectWithoutCalloutFunction',

const obj2 = {
  name: 'ObjectWithCalloutFunction',
  showName: function() {
    setTimeout(function() {
      console.log(this.name);
    }, 1000);
  }
};

obj2.showName(); // undefined(Timeout 함수의 this.name)
 

위의 예시의 경우, this는 setTimeout 함수의 스코프에 속한 this를 사용합니다.

이렇게 유동적인 this 문제점을 해결하기 위해 bind 메소드를 사용할 수 있습니다. 또는 var self = this 와 같이 추가 변수에 의도하는 this를 할당을 해도 됩니다.

// Solution 1 : this 바인딩
const obj3 = {
  name: "ObjectBinded",
  showName: function () {
    setTimeout(
      function () {
        console.log(this.name);
      }.bind(this),
      1000
    );
  },
};

// Solution 2 : self = this
const obj4 = {
  name: "ObjectSelf",
  showName: function () {
    const self = this;
    setTimeout(function () {
      console.log(self.name);
    }, 1000);
  },
};

3. Arrow Function의 등장

ES6에서 새롭게 추가된 화살표 함수는 이러한 문제를 해결하기 위해 등장했습니다. 화살표 함수는 this 바인딩을 하지 않고 언제나 상위 스코프의 this를 참조합니다. 이를 lexical this라고 합니다.

const obj4 = {
  name: "ObjectWithArrowFunction",
  showName: function () {
    setTimeout(() => {
      console.log(this.name);
    }, 1000);
  },
};

생성될 때의 상위 스코프의 this를 그대로 사용하므로, this 바인딩 문제를 신경 쓸 필요가 없습니다.

다만 이벤트 리스너의 콜백 함수에 화살표 함수를 전달하는 경우 this가 언제나 상위 객체인 window를 호출함에 주의합시다.

// HTML 요소 생성
const button = document.getElementById('button');
button.textContent = '버튼';

// 화살표 함수를 이벤트 핸들러로 등록
button.addEventListener('click', () => {
  console.log(this); // this는 window 객체를 가리킴
  console.log(this.textContent); // this는 window 객체를 가리키므로 undefined (textContent는 window 객체에 없음)
});

4. 화살표 함수의 특징

  1. 간결한 문법: 화살표 함수는 간결한 문법을 제공합니다. 특히 단일 표현식을 반환하는 경우 중괄호와 return 키워드도 생략할 수 있습니다.

    const add = (a, b) => a + b;
  2. 암묵적 반환: 중괄호가 없는 경우 표현식의 결과가 자동으로 반환됩니다.

    const square = x => x * x;
  3. this 바인딩: 화살표 함수는 고유의 this를 가지지 않기 때문에 언제나 상위 스코프의 this를 반환합니다.

profile
비전공자의 비전공자를 위한 velog

0개의 댓글