26.1 함수의 구분
JS의 함수는 일반적인 함수로써 호출할 수도 있고, new 연산자와 함께 호출하여 인스턴스를 생성할 수 있는 생성자 함수로써 호출하룻도있고, 객체에 바인딩되어 메서드로써 호출할 수도 있습니다.
ES6 이전의 모든 함수는 일반 함수로서 호출할 수 이쓴 것은 물론, 생성자 함수로서 호출할 수 있습니다. → callable이면서 constructor입니다.
callable : 호출할 수 있는 함수 객체
constructor : 인스턴스를 생성할 수 있는 함수 객체
이에 여러가지 문제가 발생할 수 있어 ES6에서는 사용목적에 따라 세 가지 종류로 명확히 구분했습니다.
26.2 메서드
ES6 사양에서 메서드는 메서드 축약 표현으로 정의된 함수만을 의미합니다.
const obj = {
x : 1,
// foo는 메서드입니다.
foo() { return this.x; }
// bar에 바인딩된 함수는 메서드가 아닌 일반 함수 입니다.
bar:function() { return this.x }
}
console.log(obj.foo()); // 1
console.log(obj.bar()); // 1
JavaScript
복사
ES6 사양에서 정의한 메서드는 인스턴스를 생성할 수 없는 non-constructor입니다.
new obj.foo() // typeerror
new obj.bar() // bar {}
JavaScript
복사
ES6 메서드는 인스턴스를 생성할 수 없으므로 prototype 프로퍼티가 없고 프로토타입도 생성하지 않습니다. 또한 표준 빌트인 객체가 제공하는 프로토타입 메서드와 정적 메서드는 모두 non-constructor 입니다.
ES6 메서드는 자신을 바인딩한 객체를 가리키는 내부 슬롯 [[HomeObject]]를 갖습니다. suepr 참조는 내부 슬롯 [[HomeObject]]를 사용하여 수퍼클래스의 메서드를 참조하므로 내수 슬롯 [[HomeObject]]를 갖는 ES6 메서드는 super 키워드를 사용할 수 있습니다.
반대로 ES6 메서드가 아닌 함수는 super 키워드를 사용할 수 없습니다. 내부 슬롯 [[HomeObject]]를 갖지 않기 때문입니다.
26.3 화살표 함수
26.3.1 화살표 함수 정의
함수 정의
화살표 함수는 함수 선언문으로 정의할 수 없고, 함수 표현식으로 정의해야 합니다.
const multiply = (x, y) => x * y;
multiply(2, 3); // -> 6
JavaScript
복사
매개변수 선언
매개변수가 여러 개인 경우 소괄호 안에 매개변수를 선언합니다.
const arrow = (x, y) => {...};
JavaScript
복사
매개변수가 한 개인 경우 소괄호 ()를 생략할 수 있습니다.
const arrow = x => { ... };
JavaScript
복사
매개변수가 없는 경우 소괄호 ()를 생략할 수 없습니다.
const arrow = () => { ... };
JavaScript
복사
함수 몸체 정의
함수 몸체가 하나의 문으로 구성된다면 함수 몸체를 감싸는 중괄호 {}를 생략할 수 있습니다. 만약 중괄호를 생략한 경우 표현식이 아닌 문이라면 에러가 발생합니다.
const power = x => x ** 2;
power(2);
// 다음과 동일합니다.
const power = x => { return x ** 2 };
JavaScript
복사
따라서 함수 몸체가 하나의 문으로 구성된다 해도 함수 몸체의 문이 표현식이 아닌 문이라면 중괄호를 생략 할 수 없습니다.
const arrow = () => { const x = 1; }
JavaScript
복사
객체 리터럴을 반환하는 경우 객체 리터럴을 소괄호로 감싸주어야 합니다.
const create = (id, content) => ({id, content });
create(1, 'Javascript');
// 위와 동일한 표현입니다.
const create = (id, content) => { return { id, content }; };
JavaScript
복사
만약 몸체가 여러개의 문으로 구성된다면 함수 몸체를 감싸는 중괄호를 생략할 수 없습니다. 또한 반환값이 있다면 명시적으로 반환해야 합니다.
화살표 함수도 즉시 실행 함수로 사용할 수 있습니다.
const person = (name => ({
sayHi() { return `Hi, My name is ${name}.`; }
}))('Lee');
console.log(person.sayHi());
JavaScript
복사
화살표 함수도 일급 객체이므로 Array.prototype,.map, Array.prototype.filter, Array.prototype.reduce 같은 고차함수에 인수로 전달할 수 있습니다. 또한 콜백함수로서 정의할 때 유용한데, 일반함수의 기능을 간략화 했으며, this도 편리하게 설계되어 있습니다.
26.3.2 화살표 함수와 일반 함수의 차이
01. 화살표 함수는 인스턴스를 생성할 수 없는 non-constructor입니다.
const Foo = () => {};
// 화살표 함수는 생성자 함수로서 호출할 수 없습니다.
new Foo(); // TypeError: Foo is not a constructor
JavaScript
복사
화살표 함수는 인스턴스를 생성할 수 없으므로 prototype 프로퍼티가 없고 프로토타입도 생성하지 않습니다.
cosnt Foo = () => {};
// 화살표 함수는 prototype 프로퍼티가 없습니다.
Foo.hasOwnProperty('prototype'); // -> false
JavaScript
복사
02. 중복된 매개변수 이름을 선언할 수 없습니다.
일반 함수는 중복된 매개변수 이름을 선언해도 에러가 발생하지 않습니다.
function normal(a, a) { return a + a;}
console.log(normal(1, 2)); // 4
JavaScript
복사
단 strict mode는 안되며, 화살표 함수에서도 중복된 매개변수 이름을 선언하면 에러가 발생합니다.
const arrow = (a, a) => a + a; // SyntaxError
JavaScript
복사
03. 화살표 함수는 함수 자체의 this, arguments, super, new.target 바인딩을 갖지 않습니다.
화살표 함수 내부에서 this, arguments, super, new.target을 참조하면 스코프 체인을 통해 상위 스코프의 this, argurments, super, new.target을 참조합니다. 만약 화살표 함수가 중첩되어있다면, 화살표함수가아닌 가장 가까운 함수를 참조합니다.
26.3.3 this
화살표 함수의 this는 일반 함수의 this와 다르게 동작합니다. 일반함수로써 호출되는 콜백 함수의 경우 일반적인 경우와 다릅니다. HOC의 인수로 전달되는 고차 함수 내부에서 호출되는 콜백함수도 중첩함수라 할 수 있습니다.
class Prefixer {
constructor(prefix){
this.prefix = prefix;
}
add(arr){
// add 메서드는 인수로 전달된 배열 arr을 순회하며 배열의 모든 요소에 prefix를 추가합니다.
// ①
return arr.map(function (item) {
return this.prefix + item; // ②
// -> typeerror : cannot read property 'prefix' of undefined
});
}
};
const prefixer = new Profixer('-webkit-');
console.log(prefixer.add(['transition', 'user-select']));
JavaScript
복사
①에서 호출한 this는 메서드를 호출한 객체(prefixer 객체)를 가리킵니다. 하지만 ②에서 가리키는 this는 undefined를 가리킵니다.왜냐하면 Array.prototype.map 메서드가 콜백 함수를 일반함수로서 호출하기 때문입니다.
이유는 class의 모든 코드에는 struct-mode가 적용되어서 전역 객체가 아닌 undefined가 바인딩 된 것 입니다.
ES6이전에는 this를 임시값에 저장하는 방식으로 문제를 해결했습니다.
결과적으로 화살표 함수는 함수 자체의 this 바인딩을 갖지 않고, 화살표 함수 내부에서 this를 참조하면 상위 스코프릐 this를 그대로 참조하며 이를 lexical this라고 합니다.
여기에 추가적으로 클래스의 메서드에서는 화살표 함수 사용을 피해야 this가 클래스 자체를 가리킬 수 있습니다.
26.3.4 super
화살표 함수 내부에서 super를 참조하면 this와 마찬가지로 상위 스코프의 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?
JavaScript
복사
26.3.5 arguments
화살표 함수는 함수 자체의 arguments 바인딩을 갖지 않아, 참조 시 상위 스코프의 arguments를 참조합니다.
(function () {
// 화살표 함수 foo의 arguments는 상위 스코프인 즉시 실행 함수의 arguments를 가리킵니다.
const foo = () => console.log(arguments); // [Arguments] { '0': 1, '1': 2 }
foo(3, 4);
}(1, 2));
// 화살표 함수 foo의 arguments는 상위 스코프인 전역의 arguments를 가리킵니다.
// 하지만 전역에는 arguments 객체가 존재하지 않습니다.
const foo = () => console.log(arguments);
foo(1, 2); // ReferenceError: arguments is not defined
JavaScript
복사
26.4 Rest 파라미터
26.4.1 기본 문법
Rest 파라미터(나머지 매개변수)는 매개변수 이름 앞에 세개의 점 …을 붙여서 정의한 매개변수를 의미하며, 함수에 전달된 인수들의 목록을 배열로 전달받습니다. 또한 일반 매개변수와도 함께 사용할 수 있습니다.
function foo(param, ...rest){
console.log(param); // 1
console.log(rest); // [1,2,3,4,5]
}
foo(1,2,3,4,5);
JavaScript
복사
단, 마지막 파라미터야 하며, 단 하나만 선언할 수 있으며, length 프로퍼티에 영향을 주지 않습니다.
function foo(...rest, param1) {}
foo(1,2,3,4,5) // SyntaxError
function foo(...rest1, ...rest2){}
foo(1,2,3,4,5) // SyntaxError
function foo(x, ...rest){}
console.log(foo.length); // 1
JavaScript
복사
26.4.2 Rest 파라미터와 arguments 객체
arguments객체는 순회 가능한 유사 배열 객체이며, 배열 메서드를 사용하기 위해서는 Function.prototype.call이나 apply 메서드를 통해 객체를 배열로 변환해야 하는 번거로움이 있습니다.
하지만 rest플 사용한다면, 배열로 직접 전달받을 수 있어 번거로움을 피할 수 있습니다.
26.5 매개변수 기본값
JS엔진은 매개변수의 갯수와 인수의 갯수를 체크하지 않기때문에 의도하지 않은 결과가 나올 수 있습니다. 따라서 전달되지 않은 경우 기본값을 할당하는 방어 코드가 필요합니다.
function sum(x = 0, y = 0) {
return x + y;
}
console.log(sum(1, 2)); // 3
console.log(sum(1)); // 1
JavaScript
복사
이는 매개변수를 전달하지 않거나, undefined를 전달할때만 적용됩니다.