반응형

 내용은 이웅모 님의 모던 "자바스크립트 DeepDive" 책을 보고 정리한 내용입니다. 저작권 보호를 위해 책의 내용은 요약되었습니다.

 

ES6 이전의 함수 특징

ES6 이전의 함수는 일반 함수 호출과 생성자 함수로 호출하는 방식이 둘 다 가능했으므로 모든 함수가 callable(호출 가능)이면서도 constructor(생성자 생성 가능)였다. 이는 언뜻 보면 편리하지만 실수를 유발시킬 수 있고, 성능 면으로서도 손해다.

 

예시)

var fn = function (){
    return 1;
}
// 1. 일반 함수로서 호출
fn()

// 2. 생성자 함수로서 호출
new fn();

// 3. 메서드로서 호출
let obj = {fn: fn};
obj.fn()

 

함수의 구분 constructor prototype super arguments
일반 함수 O O X O
메서드 X X O O
화살표 함수 X X X X

 

 

메서드란?

  • 메서드는 객체에 속한 함수로 ES6 에서 메서드 축약 표현으로 정의된 함수만을 의미한다.
  • ES6 에서 정의한 메서드는 인스턴스를 생성할 수 없는 non-constructor다.
  • 자신을 바인딩한 객체를 가리키는 내부 슬롯 [[HomeObject]] 가지고 있어 super 키워드를 사용할 수 있다.

예시)

const myObject = {
    property1: 1,
    // 일반 함수
    method1: function() {
        console.log("일반 함수 호출");
    },
    // 메서드
    method2() {
        console.log("메서드 호출");
    }
};

myObject.method1(); // 출력 : 일반 함수 호출
myObject.method2(); // 출력 : 메서드 호출

 

 

화살표 함수란?

  • 화살표 함수는 ES6에서 도입된 함수 선언의 새로운 형태로, function 키워드 대신 화살표(=>)를 사용하는 방식이다.
  • 기존 function() { } 형태를 () => {} 형태로 변경하면 된다.
  • 기존의 함수 정의 방식보다 간략하고, 내부 동작 또한 기존의 함수보다 간략하다.
  • 함수의 this 동작을 더 예측 가능하게 만들기 위해 도입되었다.

화살표 함수 정의 문법

1. 함수 선언문이 아닌 함수 표현식으로 정의해야 한다.

const arrow = (a,b) => a+b;
console.log(arrow(20,30)); // 출력 : 50

 

2. 매개변수가 한개이면 소괄호를 생략할 수 있지만 없거나 여러개인 경우 소괄호를 생략할 수 없다.

// 매개변수 여러개인 경우
const arrow1 = (a,b) => a+b;

// 매개변수 1개인 경우
const arrow2 = a => a;

// 매개변수 없는 경우
const arrow3 = () => {};

 

3. 함수 몸체가 하나의 표현식이면 몸체를 감싸는 중괄호 생략이 가능하다. 그리고 표현식인 문은 암묵적으로 반환된다.

const arrow = (a,b) => a+b;
// 암묵적으로 결과값 반환
console.log(arrow(2,3)); // 출력결과 : 5

// 표현식이 아니라 중괄호 생략 불가능
const arrow2 = (a,b) => {return a - b};
console.log(arrow2(3,2));  // 출력결과 : 1

 

4. 객체 리터럴 반환시 소괄호로 감싸야 된다. 소괄호로 감싸지 않으면 객체 리터럴의 중괄호를 몸체를 감싸는 중괄호로 잘 못 인식한다.

const arrow = (a,b) => ({a,b});
console.log(arrow(2,3)); // 출력결과 : { a: 2, b: 3 }

 

5. 화살표 함수는 즉시 실행 함수로 사용할 수 있다.

// 화살표 함수로 즉시 실행 함수 정의
const member = ((name,age) => ({
    sayHi() {return `안녕하세요 제 이름은 ${name}이고 나이는 ${age}살입니다.`; }
}))('sjmoon','28');
console.log(member.sayHi()) // 출력 : 안녕하세요 제 이름은 sjmoon이고 나이는 28살입니다.

 

6. 화살표 함수는 고차 함수에 인수로 전달할 수 있다.

const numbers = [1, 2, 3, 4, 5];

// 각 숫자를 제곱하여 새로운 배열 생성
const squaredNumbers = numbers.map(number => number * number);

console.log(squaredNumbers); // [1, 4, 9, 16, 25] 출력

 

화살표 함수와 일반 함수의 차이

1. 화살표 함수는 인스턴스를 생성할 수 없어서 프로토타입 프로퍼티가 없고 프로토타입도 생성하지 않는다. (non-constructor)

 

예시)

const Member = () => {};

console.log(Member.hasOwnProperty('prototype')); // 출력 : false

 

2. 매개변수를 중복된 이름으로 선언 할 수 없다.

 

예시)

const Member = (a,a) => {}; // Duplicate parameter name not allowed in this context

Member(1,2)

 

3. 화살표 함수 자체의 this, arguments, super, new.target 바인딩을 갖지 않는다.

 

 

화살표 함수에서의 this

콜백함수 사용시 this 바인딩 에러 상황

아래 예시 실행시 Type Error가 발생한다. 이는 Array.prototype.map메서드가 콜백함수를 일반 함수로서 호출하고 일반함수로 호출되는 모든 함수 내부의 this는 전역객체를 가리킨다. 해당 내용은 앞서 작성한 this 정리 글에서 확인할 수 있다. ES6전에는 함수의 인수로 this를 바인딩하거나 bind 메서드를 사용하여 this를 바인딩하였다.

class Member {
    constructor(name) {
        this.name = name;
    }

    add(arr){
        // arr 순회하며 name 추가
        return arr.map(function(item){
            return item + this.name       // TypeError: Cannot read properties of undefined (reading 'name')         
        })
    }
}

const member = new Member("moon");
console.log(member.add(['sj','jj']))

 

화살표 함수를 사용한 해결방법

  • 화살표 함수는 함수 자체의 this 바인딩을 갖지 않기에 함수 내부에서 this 참조시 상위 스코프의 this를 그대로 참조하고 이를 lexical this라 한다. 이는 렉시컬 스코프 처럼 this가 함수가 정의된 위치로 결정된다는 것을 말한다.
  • 화살표 함수 내부에서 this를 참조하면 일반적인 식별자처럼 스코프 체인을 통해 상위 스코프에서 this를 탐색한다.
  • 화살표 함수는 this 바인딩을 갖지않기에 메서드로 정의하거나 프로토타입 객체의 프로퍼티로 할당하는 경우 사용하지 않는 것을 추천한다. 하지만 프로토타입의 constructor와 클래스 필드 할당을 사용하여 구현하면 사용이 가능하다.

 

예시) 화살표 함수를 사용한 콜백함수 구현

class Member {
    constructor(name) {
        this.name = name;
    }

    add(arr){
        // arr 순회하며 name 추가
        return arr.map(item => this.name + item)
    }
}

const member = new Member("moon");
console.log(member.add(['sj','jj'])) // 출력 결과

 

 

super

화살표 함수는 함수 자체의 super를 가지지 않고 this와 마찬자지로 클래스 필드에서 할당한 화살표 함수 내부에서 super를 참조하면 상위스코프의 super를 가리킨다.

 

예시)

class Parent{
    constructor(name){
        this.name = name;
    }

    getName(){
        return `안녕하세요 저는 ${this.name}이라고 하고`;
    }
}

class Child extends Parent{
    constructor(name, age){
        super(name);
        this.age = age;
    }
    // super 바인딩 참조
    getName = () => `${super.getName()} 나이는 ${this.age}입니다.`
}

const child = new Child('sjmoon','28');
console.log(child.getName()); // 출력 : 안녕하세요 저는 sjmoon이라고 하고 나이는 28입니다.

 

 

arguments

화살표 함수는 함수 자체의 arguments를 가지지 않고 상위 스코프의 arguments를 참조한다.

 

예시)

(function (){
    const num = () => console.log(arguments); // 출력결과 : [Arguments] { '0': 5, '1': 6 }
    num(1,2,3,4);
}(5,6));

const num2 = () => console.log(arguments); // 전역을 가리킴
num2(5,6);

 

 

Rest 파라미터

  • 매개변수 앞에 ...을 붙여서 정의한 매개변수를 의미하는데 함수에 전달된 인수들을 배열로 전달받는다.
  • 일반 매개변수와 같이 사용할 수 있다.
  • Rest 파라미터는 함수당 하나만 선언할 수 있다.
  • Rest 파라미터 길이가 함수 객체 lengh 프로퍼티에 영향을 주지 않는다.
  • 기존의 arguments 객체는 유사 배열 객체이므로 배열로 변환해야 되는 과정이 필요했지만 Rest 파라미터는 변환 과정이 필요 없다.
  • 화살표 함수는 arguments 객체가 없기에 반드시 Rest 파라미터를 사용해야 한다.

예시)

function num(n, ...rest){
    console.log(n) // 출력 : 0
    console.log(rest) // 출력 : [ 1, 2, 3 ]
}

num(0,1,2,3)

 

 

매개변수 기본값

  • 매개변수에 기본값을 설정하여 인수를 전달받지 않는 경우 undefined가 나오는 현상을 최소화한다.
  • 매개변수 기본값은 매개변수의 개수인 함수 객체 length 프로퍼티와 arguments 객체에 영향을 주지 않는다.

예시)

function num(a,b = 3){
    // ES5 방식
    a = a || 2;
    return a * b
}

console.log(num()) // 출력 : 6
반응형

+ Recent posts