26.1 함수의 구분
- ES6 이전의 모든 함수는 일반 함수로서 호출할 수 있는 것은 물론 생성자 함수로서 호출할 수 있음
- ES6 이전의 모든 함수는 callable 이면서 constructor다
- ES6 이전에 일반적으로 메서드라고 부르던 객체에 바인딩된 함수도 callable이면서 constructor
- ES6에서는 함수를 사용 목적에 따라 세 가지 종류로 명확히 구분
ES6함수의 구분 | constructor | prototype | super | arguments |
일반 함수 | o | o | x | o |
메서드 | x | x | o | x |
화살표 함수 | x | x | x | x |
26.2 메서드
- ES6 사양에서 메서드는 메서드 축약 표현으로 정의된 함수만을 의미
- ES6 사양에서 정의한 메서드는 인스턴스를 생성할 수 없는 non - constructor
- ES6 메서드는 인스턴스를 생성할 수 없으므로 prototype 프로퍼티가 없고 프로토타입도 생성하지 않음
- ES6 메서드는 자신을 바인딩한 객체를 가리키는 내부 슬롯 [[HomeObject]]를 가짐
=> super 키워드 사용 가능
const base = {
name : 'Lee',
sayHi() {
return `Hi! ${this.name}`;
}
};
const derived ={
__proto__ : base,
//sayHi는 ES6메서드.ES6 메서드는 [[HomemObject]]를 가짐
//sayHi의 [[HomeObject]]는 sayHi가 바인딩된 객체인 derived를 가리킴
//super는 sayHi의 [[HomeObject]]의 프로토타입인 base를 가리킴
sayHi() {
return `${super.sayHi()}.how are you doing?`;
}
};
console.log(derived.sayHi()); //Hi! Lee.how are you doing?
26.3 화살표 함수
- 화살표 함수(arrow function)은 function 키워드 대신 화살표(=>)를 사용하여 기존의 함수 정의 방식보다 더 간략하게 함수 정의 가능
26.3.1 화살표 함수 정의
- 화살표 함수는 함수 표현식으로 정의해야함
const multiply = (x,y) => x*y;
multiply(2,3); //6
- 매개변수가 여러 개인 경우 소괄호 ()안에 매개변수 선언
- 매개변수가 한 개인 경우 소괄호 () 생략 가능
- 매개변수가 없는 경우 소괄호 () 생략 불가
- 함수 몸체가 하나의 문으로 구성된다면 함수 몸체를 감싸는 중괄호 {} 생략 가능
//concise body
const power1 = x => x ** 2;
power(2); //4
//block body
const power2 = x => {return x **2;};
- 함수 몸체가 하나의 문으로 구성된다 해도 함수 몸체의 문이 표현식이 아닌 문이라면 중괄호 생략 불가
const arrow = () => {const x = 1;};
- 객체 리터럴을 반환하는 경우 객체 리터럴을 소괄호 ()로 감싸 주어야 함
const create = (id,content) => ({id,content});
create(1,'JavaScript'); // {id:1, content:"JavaScript"}
- 화살표 함수도 즉시 실행 함수로 사용 할 수 있음
const person = (name => ({
sayHi() {return `Hi? My name is ${name}.`;}
}))('Lee');
console.log(person.sayHi()); //Hi? My name is Lee.
- 화살표 함수도 일급 객체이므로 Array.prototype.map, Array.prototype.filter, Array.prototype.reduce 같은 고차 함수에 인수로 전달 가능
- 화살표 함수는 콜백 함수로서 정의할 때 유리
//ES5
[1,2,3].map(function(v) {
return v * 2;
});
//ES6
[1,2,3].map(v => v*2); //[2,4,6]
26.3.2 화살표 함수와 일반 함수의 차이
1) 화살표 함수는 인스턴스를 생성할 수 없는 non_constructor이다
- 화살표 함수는 생성자 함수로서 호출 불가
2) 중복된 매개변수 이름을 선언할 수 없다
- 화살표 함수에서 중복된 매개변수 이름을 선언하면 에러 발생
3) 화살표 함수는 함수 자체의 this, arguments, super, new.target 바인딩을 갖지 않는다
- 화살표 함수 내부에서 this, arguments, super, new.target을 참조하면 스코프 체인을 통해 상위 스코프의 this, arguments, super, new.target을 참조
26.3.3 this
- 화살표 함수는 다른 함수의 인수로 전달되어 콜백 함수로 사용되는 경우가 많음
- "콜백 함수 내부의 this 문제"를 해결
콜백 함수 내부의 this 문제
class Prefixer {
constructor(prefix) {
this.prefix = prefix;
}
add(arr) {
//add 메서드는 인수로 전달된 배열 arr을 순회하며 배열의 모든 요소에 prefix를 추가
return arr.map(function(item) {
return this.prefix + item;
//undefined
});
}
}
const prefixer = new Prefixer('-webkit-');
console.log(prefixer.add['transition','user-select']);
- Array.prototype.map 메서드가 콜백 함수를 일반 함수로서 호출
-> 일반 함수로서 호출된 모든 함수 내부의 this에는 undefined가 바인딩
- 콜백 함수의 this(undefined)와 외부 함수의 thi(prefixer 객체)가 서로 다른 값을 가리키고 있기 떄문에 TypeError 발생
- 화살표 함수를 사용하여 "콜백 함수 내부의 this 문제" 해결
class Prefiexer {
constructor(prefix) {
this.prefix = prefix;
}
add(arr) {
return arr.map(item => this.prefix + item);
}
}
const prefixer = new Prefiexer('-webkit-');
console.log(prefixer.add(['transition', 'user-select']));
//[ '-webkit-transition', '-webkit-user-select' ]
- 화살표 함수는 함수 자체의 this 바인딩을 갖지 않음. 따라서 화살표 함수 내부에서 this를 참조하면 상위 스코프의 this를 그대로 참조 (lexical this)
- 화살표 함수를 Function.prototype.bind를 사용하여 표현
//화살표 함수는 상위 스코프의 this를 가리킴
() => this.x;
//익명 함수에 상위 스코프의 this를 주입. 위 화살표 함수와 동일하게 작동
(function () {return this.x;}).bind(this);
- 메서드를 화살표 함수로 정의하는 것은 피해야 함
- 메서드를 정의할 때는 ES6 메서드를 사용
const person = {
name : 'Lee',
sayHi: () => console.log(`Hi ${this.name}`)
};
//sayHi 프로퍼티에 할당된 화살표 함수 내부의 this는 상위 스코프인 전역의 this가 가리키는
//전역 객체를 가리키므로 this.name은 빈 문자열을 갖는 window.name과 같음
//전역 객체 window에는 빌트인 프로퍼티 name이 존재
person.sayHi(); //Hi undefined
26.3.4 super
- 화살표 함수는 함수 자체의 super 바인딩을 갖지 않음. 화살표 함수 내부에서 super를 참조하면 상위 스코프의 super을 참조
- super는 내부 슬롯 [[HomeObject]]를 갖는 ES6 메서드 내에서만 사용할 수 있는 키워드
- 화살표 함수는 ES6 메서드는 아니지만 함수 자체의 super 바인딩을 갖지 않으므로 super을 참조해도 에러가 발생하지 않고 constructor의 super 바인딩을 참조
class Base {
constructor(name) {
this.name = name;
}
sayHi() {
return `Hi! ${this.name}`;
}
}
class Derived extends Base {
//화살표 함수의 super는 상위 스코프인 constructor의 super을 가리킴
sayHi = () => `${super.sayHi()} how are you doing?`;
}
const derived = new Derived('Lee');
console.log(derived.sayHi()); //Hi! Lee how are you doing?
26.3.5 arguments
- 화살표 함수는 함수 자체의 arguments 바인딩을 갖지 않음. 화살표 함수 내부에서 arguments를 참조하면 상위 스코프의 arguments를 참조
-arguments 객체는 함수를 정의할 때 매개변수의 개수를 확정할 수 없는 가변 인자 함수를 구현할 때 유용
- 화살표 함수로 가변 인자 함수를 구현해야 할 때는 Rest 파라미터 사용
26.4 Rest 파라미터
26.4.1 기본 문법
- 매개변수 이름 앞에 세개의 점(...)을 붙여서 정의한 매개변수
- Rest 파라미터는 함수에 전달된 인수들의 목록을 배열로 전달받음
function foo(...rest) {
//매개변수 rest는 인수들의 목록을 배열로 전달받는 Rest 파라미터
console.log(rest); //[ 1, 2, 3, 4, 5 ]
}
foo(1,2,3,4,5);
- 먼저 선언된 매개변수에 할당된 인수를 제외한 나머지 인수들로 구성된 배열이 할당
- Rest 파라미터는 반드시 마지막 파라미터이어야 함
- Rest 파라미터는 단 하나만 선언 가능
- Rest 파라미터는 함수 객체의 length 프로퍼티에 영향을 주지 않음
26.4.2 Rest 파라미터와 arguments 객체
- arguments 객체는 함수 호출시 전달된 인수(argument)들의 정보를 담고 있는 순회 가능한 유사 배열 객체이며 함수 내부에서 지역 변수처럼 사용가능
- arguments 객체는 배열 메서드를 사용하려면 arguments 객체를 배열로 변환해야 하는 번거로움 존재
- Rest 파라미터를 사용하면 가변 인자 함수의 인수 목록을 배열로 직접 전달 받을 수 있음
function sum(...args) {
//Rest 파라미터 args에는 배열 [ 1, 2, 3, 4, 5 ]가 할당됨
return args.reduce((pre,cur) => pre+cur,0);
}
console.log(sum(1,2,3,4,5)); //15
26.5 매개변수 기본값
- ES6에서 도입된 매개변수 기본값을 사용하면 함수 내에서 수행하던 인수 체크 및 초기화 간소화 가능
function sum(x=0, y=0) {
return x+y;
}
console.log(sum(1,2)); //3
console.log(sum(1)); //1
- Rest 파라미터에는 기본값 지정 불가
- 매개변수 기본값은 함수 객체의 length 프로퍼티와 arguments 객체에 아무런 영향도 주지 않음
'JavaScript' 카테고리의 다른 글
[Deep dive] 27장 배열(2) (0) | 2023.08.16 |
---|---|
[Deep dive] 27장 배열(1) (0) | 2023.08.16 |
[Deep dive] 25장 클래스 (2) (0) | 2023.08.16 |
[Deep dive] 25장 클래스 (1) (0) | 2023.08.15 |
[Deep dive] 24장 클로저 (0) | 2023.08.14 |