별다른 구분 없이 다양한 목적으로 사용됨
ES6 이전의 모든 함수는 일반 함수로서 호출할 수 있는 것은 물론 생성자 함수로서 호출할 수 있음 ❗️
var foo = function() {
return 1;
};
foo(); // 일반 함수 : 1
new foo(); // 생성자 함수 : foo {}
var obj = { foo: foo };
obj.foo(); // 메서드 : 1
// 프로퍼티 f에 바인딩된 함수는 callable + constructor
var obj = {
x: 10,
f: function() { return this.x; }
};
// f에 바인딩된 함수를 메서드로서 호출
console.log(obj.f()); // 10
// f에 바인딩된 함수를 일반 함수로서 호출
var bar = obj.f;
console.log(bar()); // undefined
// f에 바인딩된 함수를 생성자 함수로서 호출
console.log(new obj.f()); // f {}
→ 혼란스럽고, 실수를 유발할 가능성이 있으며 성능에 좋지 않음
ES6 함수 구분 | constructor | prototype | super | arguments |
---|---|---|---|---|
일반 함수 (normal) | O | O | X | O |
메서드 (method) | X | X | O | O |
화살표 함수 (Arrow) | X | X | X | X |
일반 함수
메서드 / 화살표 함수
ES6에서의 메서드
: 메스드 축약 표현으로 정의된 함수만을 의미
ES6에서 정의한 메서드는 인스턴스를 생성할 수 없는 non-constructor
ES6 메서드는 인스턴스를 생성할 수 없으므로 prototype 프로퍼티가 없고 프로토타입도 생성하지 않음
ES6 메서드는 자신을 바인딩한 객체를 가리키는 내부 슬롯 [[HomeObject]]
를 가짐
[[HomeObject]]
를 사용하여 수퍼클래스의 메서드를 참조하므로 내부 슬롯 [[HomeObject]]
를 갖는 ES6 메서드는 super
키워드를 사용할 수 있음[[HomeObject]]
를 갖지 않기 때문에 super
키워드를 사용할 수 없음const obj = {
x: 1,
foo() { return this.x; }, // 메서드
bar: function() { return this.x; } // 일반 함수
};
console.log(obj.foo()); // 1
console.log(obj.bar()); // 1
// ES6 메서드는 인스턴스 생성 X
new obj.foo(); // TypeError: obj.foo is not a constructor
new obj.bar(); // bar {}
// ES6 메서드는 prototype 프로퍼티 X
obj.foo.hasOwnProperty('prototype'); // false
obj.bar.hasOwnProperty('prototype'); // true
화살표 함수
function 키워드 대신 화살표를 사용하여 기존의 함수 정의 방식보다 간략하게 함수를 정의하는 방법
함수 표현식으로 정의해야 함
호출 방식은 기존 함수와 동일
const multiply = (x, y) => x * y;
multiply(2, 3); // 6
const multiply = (x, y) => x * y;
multiply(2, 3); // 6
const arrow = x => {...};
const arrow = () => {...};
화살표 함수는 인스턴스를 생성할 수 없는 non-constructor
중복된 매개변수 이름을 선언할 수 없음
함수 자체의 this, arguments, super, new.target 바인딩을 갖지 않음
화살표 함수는 함수 자체의 this
바인딩을 갖지 않음
this
를 참조하면 상위 스코프의 this를 그대로 참조 (lexical this)lexical this
렉시컬 스코프와 같이 화살표 함수의 this
가 함수가 정의된 위치에 의해 결정된다
화살표 함수가 전역 함수라면 화살표 함수의 this
는 전역 객체 ❗️
const foo = () => console.log(this);
foo(); // window
this
바인딩을 갖지 않기 때문에 Function.prototype.call
, Function.prototype.apply
, Function.prototype.bind
를 사용해서 화살표 함수 내부의 this
를 교체할 수 없음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());
(function () {
const foo = () => console.log(arguments); // [Arguments] { '0': 1, '1': 2 }
foo(3, 4);
}(1, 2));
const foo = () => console.log(arguments);
foo(1, 2); // ReferenceError: arguments is not defined
Rest 파라미터 (나머지 매개변수)
: 매개변수 이름 앞에 세개의 점...
을 붙여 정의한 매개변수
function foo(...rest){
console.log(rest); // [1, 2, 3, 4, 5]
}
foo(1, 2, 3, 4, 5);
function foo(param1, param2, ...rest){
console.log(param1); // 1
console.log(param2); // 2
console.log(rest); // [3, 4, 5]
}
foo(1, 2, 3, 4, 5);
// Rest 파라미터는 반드시 마지막 파라미터여야 함
function foo(...rest, param1, param2){}
foo(1, 2, 3, 4, 5);
// SyntaxError: Rest parameter must be last formal parameter
// Rest 파라미터는 단 하나만 선언할 수 있음
function foo(...rest1, ...rest2){}
foo(1, 2, 3, 4, 5);
// SyntaxError: Rest parameter must be last formal parameter
function foo(...rest) {}
console.log(foo.length); // 0
function bar(x, ...rest) {}
console.log(bar.length); // 1
function baz(x, y, ...rest) {}
console.log(baz.length); // 2
ES6 Rest 파라미터를 사용하여 가변 인자 함수의 인수 목록을 배열로 직접 전달받을 수 있음
유사 배열 객체인 arguments 객체를 배열로 변환하는 번거로움을 피할 수 있음
function sum(...args) {
return args.reduce((pre, cur) => pre + cur, 0);
}
console.log(sum(1, 2, 3, 4, 5)); // 15
함수 호출 시 매개변수의 개수만큼 인수를 전달하는 것이 바람직하지만, 그렇지 않은 경우에도 에러 발생 X
인수가 전달되지 않은 매개변수 값은 undefined
function sum(x, y) {
return x + y;
}
console.log(sum(1)); // NaN
function sum(x, y) {
x = x || 0;
y = y || 0;
return x + y;
}
console.log(sum(1, 2)); // 3
console.log(sum(1)); // 1
function sum(x = 0, y = 0) {
return x + y;
}
console.log(sum(1, 2)); // 3
console.log(sum(1)); // 1
function logName(name = 'Lee') {
console.log(name);
}
logName(); // Lee
logName(undefined); // Lee
logName(null); // null
function foo(...rest = []) {
console.log(rest);
} // SyntaxError: Rest parameter may not have a default initializer
function sum(x, y = 0){
console.log(arguments);
}
console.log(sum.length); // 1
sum(1); // Arguments { '0': 1 }
sum(1, 2); // Arguments { '0': 1, '1': 2 }