study: javascript | 숨참고 deep dive (26) ES6 함수의 추가 기능

Lumpen·2023년 3월 31일
0

Study

목록 보기
27/92

함수의 구분

ES6 이전 자바스크립트의 함수는 구분 없이 다양한 목적으로 사용되었다
자바스크립트의 함수는 일반적인 함수로서 호출할 수도 있고
new 연산자와 함께 호출하여 인스턴스를 생성할 수 있는 생성자 함수로서 호출할 수도 있으며
객체에 바인딩되어 메서드로서 호출할 수도 있다
이는 편리하지만 실수를 유발할 수 있다
ES6 이전 모든 함수는 일반함수 + 생성자 함수로의 기능
callable 이면서 constructor 다

ES6 이전 메서드라고 부르던 객체에 바인딩된 함수도 
callable 이며 constructor 다

이는 문법상 가능한 것으로 문제가 있고 성능에도 좋지 않다
메서드나 콜백 함수도 constructor 이기 때문에
불필요한 프로토타입 객체를 생성한다

ES6 부터는 이러한 것을 해결하기 위해 세 가지로 함수를 구분한다

  • 일반 함수: constructor, prototype, arguments, this
  • 메서드: super, arguments, this
  • 화살표 함수: this 바인딩도 없는 진정한 의미의 일반 함수

일반 함수는 함수 선언문이나 표현식으로 작성한 함수
화살표 함수는 non-cunstructor 다

메서드

ES6 이전 사양에서는 메서드에 대한 정의가 없었다
객체에 바인딩 된 함수르 메서드라고 불렀다
ES6 사양에서 메서드는 메서드 축약 표현으로 정의된 함수만을 의미

ES6 메서드는 인스턴스를 생성할 수 없는 non-constructor 다
화살표 함수나 메서드는 non-constructor 이기 때문에
프로토타입을 생성하지 않고 prototype 프로퍼티도 가지지 않는다
표준 필트인 객체가 제공하는 프로토타입 메서드와 정적 메서드는 모두 non-constructor 다
ES6 메서드는 자신을 바인딩한 객체를 가리키는 내부 슬롯 [[HomeObject]] 를 갖는다
super 참조는 내부 슬롯 [[HomeObject]] 를 사용하여 수퍼 클래스의 메서드를 참조하므로 메서드는 super 키워드를 사용할 수 있다
메서드가 아닌 함수는 super 키워드를 사용할 수 없다

화살표 함수

화살표 함수는 기존 함수 정의 방식보다 간략하게 함수를 정의할 수 있다
표현만 간단한 것이 아니라 내부 동작도 간략하다
특히 화살표 함수는 콜백 함수 내부에서 this 가 전역 객체를 가리키는 문제를 해결하기 위한 대안으로 유용하다

화살표 함수도 즉시 실행 함수로 사용 가능
화살표 함수도 일급 객체이므로 고차 함수에 인수로 전달할 수 있다

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

  • 화살표 함수는 인스턴스를 생성할 수 없는 non-constructor
  • 화살표 함수는 중복된 매개변수 이름을 선언할 수 없다 (일반 함수는 가능)
  • this, arguments, super, new.target 바인딩을 갖지 않는다
    -> 상위 스코프의 this, arguments, super, new.target 을 참조하게 된다

this

화살표 함수와 일반 함수가 구별되는 가장 큰 특징은 this
화살표 함수는 다른 함수의 인수로 전달되어 콜백으로 사용되는 경우가 많다
화살표 함수는 일반 함수 내부의 this 문제를 해결하는데 사용하기 좋다
콜백 함수도 일반 함수로 작성하면 내부 this 애 전역 객체 혹은 undefined 가 바인딩 된다
고차 함수의 인수로 전달되는 콜백 함수도 중첩 함수이기 때문이다
화살표 함수는 함수 자체의 this 바인딩을 갖지 않기 때문에 화살표 함수 내부에서 this 를 참조하면 상위 스코프의 this 를 그대로 참조한다
이를 lexical this 라고 한다
렉시컬 스코프와 같이 화살표 함수의 this 가 함수가 정의된 위치에 의해 결정되는 것을 의미한다

화살표 함수를 제외한 모든 함수에는 this 바인딩이 존재한다
화살표 함수가 도입되기 이전에는 일반적인 식별자처럼 스코프 체인을 통해
this 를 탐색할 필요가 없었다
화살표 함수는 this 바인딩이 존재하지 않기 때문에 스코프 체인을 통해 상위 스코프에서 this 를 탐색하게 된다

화살표 함수가 중첩되어 있다면 마찬가지로 중첩된 최상위 함수의 상위 스코프의 this 를 참조하게 된다
프로퍼티에 할당한 화살표 함수도 스코프 체인 상에서 가장 가까운 상위 함수의 this 를 참조하게 된다

화살표함수는 this 바인딩을 갖지 않기 때문에 call, apply, bind 메서드를 사용해도 내부의 this 를 교체할 수 없다
각각 메서드를 호출할 수는 있지만 this 가 언제나 상위 스코프의 this 를 참조하게 된다

일반적인 메서드도 화살표 함수로 작성하는 것은 피해야 한다

const Person = {
	name: 'Lee',
  	sayHi : () => console.log(`hi ${this.name}`)
}

위 예제에서 sayHi 메서드 내부 this 는 Person 객체를 가리키지 않고
상위 스코프인 전역의 this 가 가리키는 전역 객체를 가리키게 된다
프로토타입 객체의 프로퍼티에 함수를 할당하는 경우에도 동일한 문제가 발생한다

프로퍼티를 동적 추가할 때는 ES6 메서드 정의를 사용할 수 없으므로 일반 함수를 할당한다

ES6 메서드를 동적 추가하고 싶다면 객체 리터럴을 바인딩하고 프로토타입의 constructor 프로퍼티와 생성자 함수 간의 연결을 재설정해야 한다

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

Person.prototype = {
	constructor: Person,
  	sayHi () {console.log(`${this.name} hi`)}
}

const person = new Person('Lee')
person.sayHi() 

클래스 필드에 화살표 함수를 할당할 수 있다

// bad

class Person {
	name = 'Lee'
	sayHi = () => console.log(`${this.name} hi`)
}

이 때 화살표 함수로 작성된 클래스 필드 내부에서의 this 는 상위 스코프를 가리킨다
클래스 필드의 상위 스코프는 constructor 다
따라서 화살표 내부에서 참조한 this 는 constructor 내부의 this 바인딩과 같다
constructor 내부의 this 바인딩은 클래스가 생성한 인스턴스를 가리키므로
위 화살표 함수는 프로토타입 메서드가 아닌 인스턴스 메서드가 된다
따라서 메서드를 정의할 때는 메서드 축약 표현이 좋다


// 위 bad 코드와 같음
class Person {
  	constrcutor () {
    	this.name = 'Lee'
		this.sayHi = () => console.log(`${this.name} hi`)
    }
}

super

화살표 함수는 함수 자체의 super 바인딩을 갖지 않는다
따라서 상위 스코프의 super 를 참조하게 된다
super 는 내부 슬롯 [[HomeObject]] 를 갖는 ES6 메서드 내에서만 사용할 수 있다
클래스 내부에서 화살표 함수로 작성된 인스턴스 메서드의 super 는 상위 스코프의 super 가 바인딩 된다

arguments

화살표 함수는 arguments 바인딩을 가지지 않기 때문에 상위 스코프의 arguments 를 참조하게 된다
화살표 함수로 가변 인자 함수를 구현해야 할 때는 반드시 Rest 파라미터 문법을 사용한다

Rest 파라미터

가변 인자 인수들의 목록을 배열 형식으로 전달받는다
일반 매개변수와 함께 사용하고 Rest 파라미터는 이름과 같이
나머지, 마지막 파라미터여야 한다
Rest 파라미터는 하나만 사용할 수 있다

function foo(a, ...rest) {
  	console.log(a) // 1
	console.log(rest) // [2, 3]
}
foo(1, 2, 3)

Rest 파라미터와 arguments 객체

arguments 객체는 함수 호출 시 전달된 인수들의 정보를 담고 있는 순회 가능한
유사 배열 객체며 함수 내부에서 지역 변수처럼 사용할 수 있다
하지만 유사 배열 객체이므로 배열 메서드 사용이 번거롭다

매개변수 기본 값

함수 호출 시 매개변수 개수만큼 인수를 전달하는 것이 바람직하지만
그렇지 않아도 에러가 발생하지는 않는다
자바스크립트 엔진은 매개변수 개수와 인수의 개수를 체크하지 않음
전달되지 않은 인수는 undefined, 초과된 인수는 무시된다

profile
떠돌이 생활을 하는. 실업자는 아니지만, 부랑 생활을 하는

0개의 댓글