일반적으로 프로그래밍에서 함수는 입력(input)을 받아 출력(output)을 내보내는 일련의 과정을 정의한 것으로 하나의 실행 단위이다.
typeof function (){} === 'function';
typeof
연산자는 피연산자가 함수이면 function
을 반환해서 오해할 수 있나 함수는 top-level 빌트인 타입이 아니라 다만 object
의 서브타입 중 하나이다. 즉, 자바스크립트의 함수는 객체이다.
함수는 일반 객체와 달리 호출할 수 있는 객체(callable object)이다. 호출할 수 있는 객체는 일반 객체가 가지는 내부 슬롯과 내부 메서드에 더하여 추가적인 내부 메서드와 내부 슬롯을 가진다.
내부 슬롯과 내부 메서드에 대해서는 Internal Slot and Internal Method를 참고한다.
일급 객체는 다음과 같은 조건을 만족한다.
- 이름 없는 리터럴로 생성할 수 있다. (런타임에 생성이 가능하다.)
- 변수나 자료구조(객체, 배열 등)에 할당할 수 있다.
- 함수의 매개변수에 전달할 수 있다.
- 함수의 반환값으로 사용할 수 있다.
자바스크립트의 함수는 값으로 사용될 수 있는 **일급 객체(first-class object)**이다. 함수는 다른 함수의 인수로 전달되거나 반환값이 될 수 있고 다른 어떤 자바스크립트의 값이 사용되는 것처럼 사용될 수 있다.
자바스크립트에서 메모리 공간에 생성된 객체는 변수에 할당한 후 식별자를 사용하여 참조할 수 있다. 함수는 객체이므로, 변수에 할당한 후 식별자를 사용하여 참조해야한다. 즉 식별자를 사용해 함수를 참조하고 호출할 수 있다.
- 함수를 정의하여 함수를 생성한다.
- 함수를 호출하여 함수를 실행한다.
**함수 정의(function definition)**는 함수의 이름, 매개변수, 함수 본문으로 구성된다.
- 함수의 이름은 자바스크립트 식별자이다. 함수 본문 안에서만 참조할 수 있다.
- **매개변수(parameter)**는 함수 내부로 입력을 전달받는 변수이다. 함수 본문 안에서만 참조할 수 있다.
- 함수 본문(function body) 혹은 함수 몸체는 일련의 문들을 코드 블록(
{}
)으로 감싼 것이다. 출력인 **반환값(return value)**을 내보내는 반환문(return statement)을 포함한다.
/* 함수 정의 */
function add(x, y) {
return x + y
}
함수를 정의하는 방법은 12.3 함수 정의하기를 참고한다.
**함수 호출(function call/invoke)**는 인수를 함수에 전달하여 함수의 실행을 명시한다.
- **인수(argument)**는 함수 내부로 전달하고자 하는 입력값으로, 매개변수를 통해 함수에 전달된다.
/* 함수 호출 및 함수 실행 */
add(1, 2); // 3
함수 리터럴은 function
키워드, 함수 이름, 매개변수 목록, 함수 몸체로 구성된다. 리터럴은 평가되어 값을 생성할 수 있으므로, 함수 리터럴 역시 평가되어 객체 값을 생성하고 변수에 할당될 수 있다.
let foo = function add(a, b) {
return a + b;
};
식별자 foo
를 선언하여 확보하여 메모리 공간에는 함수 리터럴이 평가되어 생성된 객체가 저장된 메모리 공간을 참조하게 된다. 함수 리터럴로 함수를 정의하는 방식은 12.3 함수 정의하기 - 함수 표현식을 참고한다.
자바스크립트에서 함수를 정의하는 방법은 아래와 같다.
- 함수 선언(function declaration):
function
문 - 함수 표현식(function expression):
function
표현식 - 화살표 함수식(arrow function expression)
Function
생성자
자바스크립트에서 제너레이터 함수(generator function)을 정의하는 방법은 아래와 같다.
- 생성기 함수 선언(generator function declaration)
- 생성기 함수 표현식(generator function expression)
GeneratorFunction
생성자
**함수 선언문(function statement)**은 함수 리터럴과 동일한 형태를 가진다.
function 함수이름(파라미터1, ...) {
// 함수 본문
}
function add(a, b) {
return a + b;
}
단, 함수 리터럴과 달리 함수 이름을 생략할 수 없으며 값으로 평가될 수 없으므로 표현식이 아닌 문이다.
function (a, b) {
return a + b;
}
// SyntaxError: Function statements require a function name
함수 선언문 자체가 값으로 평가되지 않을 뿐, 자바스크립트 엔진은 함수 선언문을 평가하여 함수 객체를 생성하고 그 과정에서는 값이 평가된다.
함수 이름은 함수 본문에 지역적이므로 함수 외부에서는 해당 이름으로 함수를 참조할 수 없다. 하지만 함수 선언으로 생성한 함수는 함수 외부에서 함수 이름을 사용하여 함수를 참조할 수 있는 것처럼 보인다.
function foo() {
console.log('foo');
}
foo();
이는 자바스크립트 엔진이 암묵적으로 함수 이름과 동일한 식별자를 생성하고 함수 객체를 할당하기 때문이다.
자바스크립트 엔진은 모든 선언문을 런타임 이전에 실행한다. 함수 선언문 역시 호이스팅되므로, 함수 선언문으로 정의한 함수의 생성 시점은 런타임 이전이다.
console.log(foo); // ƒ foo() { console.log('foo'); }
foo(); // 'foo'
function foo() { console.log('foo'); };
12.10 함수 호이스팅을 참고한다.
**함수 표현식(function expression)**은 객체 리터럴을 변수에 할당하여 함수를 생성하는 방식이다. 객체 리터럴에서 함수 이름을 생략하는지에 따라 다음과 같이 나눌 수 있다.
- 기명 함수(NFE; named function expression)
- 익명 함수(anonymous function) 혹은 무명 함수(unnamed function expression)
- **기명 함수(named function expression)**는 이름이 있는 함수이다.
function 함수이름 (파라미터1, ...) {
// 함수 본문
}
let factorial = function foo(n) {
if (n <= 1) return 1;
return n * foo(n - 1);
}
factorial(5); // 120
foo(5); // ReferenceError: foo is not defined
함수 이름은 함수 본문에 지역적이므로 외부에서 참조하려면 함수가 할당된 변수 이름을 사용한다.
- **익명 함수(anonymous function expression)**은 이름이 없는 함수이다. 익명 함수를 사용하는 것이 일반적이다.
function (파라미터1, ...) {
// 함수 본문
}
const add = function (a, b) {
return a + b;
};
add(1, 2); // 3
익명 함수를 사용하면 기명 함수의 factorial
재귀 구현처럼 함수가 자신의 본문 안에서 자기 자신을 참조할 수 없으므로 이 경우 기명 함수를 사용하도록 한다.
자바스크립트 엔진은 모든 선언문을 런타임 이전에 실행한다. 이때 변수 선언은 호이스팅되지만 할당 부분은 런타임에 평가되므로, 함수 표현식으로 정의한 함수의 생성 시점은 런타임 이후이다.
console.log(foo); // undefined
foo(); // TypeError: foo is not a function
var foo = function() { console.log('foo'); };
12.10 함수 호이스팅을 참고한다.
자바스크립트 엔진은 기명 함수 리터럴을 문맥에 따라 함수 선언문 또는 함수 리터럴 표현식으로 해석한다.
- 단독으로 사용되는 경우 함수 선언문으로 해석한다.
function add(a, b) {
return a + b;
}
add(1, 2); // 3
- 값으로 평가되어야 하는 문맥에서는 함수 리터럴 표현식으로 해석한다.
/* 값으로서 변수에 할당되는 경우 */
const foo = function add(a, b) {
return a + b;
};
foo(1, 2); // 3
/* 값으로서 피연산자에 사용되는 경우 */
console.log(function add(a, b) { return a + b; }); // ƒ add(a, b) { returna + b; }
ES6 **화살표 함수(arrow function)**는 function
키워드가 아닌 화살표(=>
)를 사용한다.
const 변수이름 = (파라미터1, ...) => {
// 함수 본문
}
화살표 함수에 대해서는 Arrow function을 참고한다.
함수는 Function
의 인스턴스이므로 new
연산자를 이용하여 생성할 수 있다.
new Function(파라미터1, ..., 함수본문)
파라미터
는,
로 구분한 식별자이거나, 식별자가,
로 구분된 문자열이다.함수본문
은 문자열이다.new
연산자는 생략할 수 있다.
const add = new Function('a, b', 'return a + b');
Function
생성자로 함수를 생성하는 방식은 권장되지 않는다. 또한 함수 선언문이나 함수 표현식으로 생성한 함수와 다르게 동작한다. 렉시컬 스코프를 만들지 않고 전역 함수처럼 스코프를 생성하여 클로저를 만들지 않는다.
- 자바스크립트에서 함수의 이름은 식별자이다.
- 함수 이름은 함수 본문 내에서만 참조할 수 있다.
- 함수 객체는 함수 이름을 값으로 가지는
name
프로퍼티를 가진다.
- 함수 선언문으로 정의한 함수의
name
프로퍼티는 함수 선언문의 함수 이름을 값으로 가진다.
function foo(){};
console.log(foo.name); // 'foo'
- 기명 함수 표현식으로 정의한 함수의
name
프로퍼티는 함수 리터럴의 함수 이름을 값으로 가진다.
const bar = function foo(){};
console.log(bar.name); // 'foo'
- 익명 함수 표현식과 화살표 함수 표현식으로 정의한 함수의
name
프로퍼티는 함수 리터럴이 할당된 변수 이름을 값으로 가진다. 암묵적 이름이라고 한다.
const bar = function(){};
console.log(bar.name); // 'bar'
단, 익명 함수 표현식은 ES5에서 빈 문자열을 값으로 가진다.
- 함수가 값을 반환하려면 함수 본문에
return
문을 작성한다.
const add = (a, b) => {
return a + b;
};
return
문이 없는 함수는 암묵적으로 기본값으로undefined
를 반환한다.- 단,
new
키워드로 호출되는 생성자는 자신의this
매개변수값을 반환한다.
- 단,
const foo = () => {};
console.log(foo()); // undefined
- 함수 본문 외부에서
return
문을 사용하면SyntaxError
가 발생한다. (단, Node.js는 모듈 시스템에 의해 파일별로 독립적인 파일 스코프를 가지므로 파일의 가장 바깥에서 반환문을 사용해도 에러가 발생하지 않는다.)
return 1; // SyntaxError: Illegal return statement
- 함수 이름 뒤에 인자를 함수 호출 연산자
()
로 감싸 함수를 호출할 수 있다. 함수를 호출하면 함수는 실행 결과인 반환값을 반환한다.
const add = (a, b) => a + b;
add(1, 2); // 3
- 함수 호출은 값으로 평가될 수 있는 표현식이다. 즉, 함수 호출의 결과인 함수의 반환값과 동치이다.
add(1, 2) === 3; // true
(() => {})() === undefined; // true
- 함수는 **매개변수(parameter)**를 통해 인자(argument)를 함수 내부로 전달받는다.
- 매개변수는 함수 본문에 지역적인 것으로 취급된다. 즉, 함수가 호출될 때 지역 변수처럼 선언되어
undefined
로 초기화된다. 따라서 전달된 인자가 없으면 재할당이 일어나지 않으므로undefined
로 접근된다.
const foo = (a) => { console.log(a); };
foo(); // undefined
- 매개변수의 개수와 인수의 개수가 일치하지 않아도 에러는 발생하지 않는다.
const foo = (a, b) => { console.log(a + b); }
foo(1); // NaN: a에 1이 전달되고 b에는 아무것도 전달되지 않았으므로 undefined로 초기화됨
foo(1, 2, 3); // 3: 초과된 인자는 무시된다.
- ES6에 다음 두 종류의 매개변수가 도입되었다.
- 기본 매개변수(default parameter)
- 나머지 매개변수(rest parameter)
- ES6 **기본 매개변수(default parameter)**는 매개변수에 기본값을 지정할 수 있도록 한다.
- 매개변수에 전달된 값이 없거나
undefined
값이 전달된 경우, 인자는 지정한 기본값으로 초기화된다.
const add = (a = 0, b = 0) => a + b;
add(1); // 1
add(undefined, undefined); // 0
add(); // 0
- 기본 인수는 호출할 때마다(at call time) 평가된다. 따라서 파이썬과 달리 함수가 호출될 때마다 새로운 객체가 생성된다.
function append(item, array = []) {
array.push(item);
return array;
}
append(1); // [1]
append(2); // [1, 2]가 아니라 [2]가 반환된다.
- 앞쪽의 매개변수는 뒤쪽의 매개변수에 사용할 수 있다.
function foo(a, b = a){
return b;
}
foo(3);
- ES6 구조 분해 할당(destructing assignment)을 사용할 수 있다.
const foo = ([x, y] = [0, 1]) => {
return x + y;
}
foo(); // 1
foo([1, 2]); // 3
기본 매개변수가 한 개 이상 정의되면 파라미터 리스트 내의 식별자들에 대하여 second scope가 만들어진다.
- 함수 본문에 선언된 식별자들은 매개변수 기본값을 초기화할 때 사용할 수 없다. (
ReferenceError
발생)
const foo = (b = a) => {
const a = 1;
}
foo(); // ReferenceError: a is not defined
- 함수 본문에
var
로 선언된 변수는 동일한 이름을 가진 매개변수를 가리키지 않는다.
const foo = (a, b = a) => {
var a = 1;
console.log(b);
}
foo(); // undefined
- ES6 **나머지 매개변수(rest parameter)**는 가변 인수를 배열로 나타낼 수 있게 한다.
const foo = (...args) => typeof(args);
foo(); // 'object'
const add = (...args) => args.reduce((acc, cur) => acc + cur, 0)
add(1, 2, 3); // 6
add(...[1, 2, 3]); // 6
- 파라미터가 여러 개라면 나머지 매개변수는 모든 파라미터 중 가장 마지막에 위치해야 한다.
const add = (a, b, ...rest) => a + b + rest.reduce((acc, cur) => acc + cur, 0);
add(1, 2, 3); // 6
const add = (...rest, a, b) => a + b + rest.reduce((acc, cur) => acc + cur, 0);
// SyntaxError: Rest parameter must be last formal parameter
함수의 length
프로퍼티는 함수를 정의할 때 매개변수 개수를 저장한다.
function foo(a, b) {};
foo.length; // 2
- 함수를 호출할 때 **인수(argument)**를 매개변수를 통해 함수 내부로 전달할 수 있다. 인수는 전달된 순서대로 매개변수에 할당된다.
- 인수의 개수와 매개변수의 개수는 일치하지 않을 수 있다. 인수가 매개변수보다 적은 경우 남는 매개변수에는
undefined
가 할당되며 인수가 매개변수보다 많은 경우 남는 인수는 무시된다.
함수의 arguments
프로퍼티는 함수의 인수들을 저장하는 arguements
객체로 iterable하다.
- 함수 내부에서 함수의 인수 리스트를 가져오려면
arguements
객체를 사용한다.
function foo(a, b, c) {
return arguments[0];
}
foo(1, 2, 3); // 1
- 인덱스를 통해 각 인수에 접근할 수 있으며, 심지어 재할당할 수도 있다.
function foo(a) {
arguments[0] = 3;
return a;
}
foo(1); // 3
arguments.length
프로퍼티는 함수를 호출할 때 인수의 개수를 저장한다. 인수의 개수는 파라미터의 개수와 일치하지 않을 수 있다.
function foo(a, b) {
return arguments.length;
}
foo(); // 0
foo(1, 2); // 2
foo(1, 2, 3); // 3
arguments.callee
프로퍼티는arguments
객체를 생성한 함수, 즉 함수 자신을 가리킨다.
function foo() {
console.log(arguments.callee);
}
// ƒ foo() { console.log(arguments.callee); }
arguments
객체는 유사 배열 객체(array-like object)로Array
타입의 값이 아니므로, 배열처럼 사용하려면 배열로 변환하거나 배열 메서드를 간접 호출해야한다.
/* 함수 본체 내부 */
// 배열로 변환하기
let args = Array.from(arguments);
args = [...arguments;]
// 배열 메서드를 간접적으로 호출하기
args = Array.prototype.slice.call(arguments);
배열 메서드를 간접 호출하기 위해 ES5의 Function.prototype.call
과 Function.prototype.apply
를 사용했다. Function.prototype.call/apply
를 참고한다.
이러한 번거로움을 피하기 위해 ES6의 나머지 매개변수가 도입되었다.
- 화살표 함수에서는
arguments
객체를 바인드하지 않는다. 따라서 가능하다면 나머지 매개변수를 사용하여 구현하도록 한다.
const foo = (a, b, c) => arguments.length;
foo(1, 2, 3); // ReferenceError: arguments is not defined
const bar = (...rest) => rest.length;
bar(1, 2, 3); // 3
- 나머지 매개변수와
arguments
객체는 다루는 대상이 다르다.- 나머지 매개변수: 가변 인수들만을 대상으로 한다.
arguments
객체: 함수로 전달된 모든 인수를 대상으로 한다.
function foo(a,...rest) {
console.log(`rest의 개수: ${rest.length}`);
console.log(`arguments의 개수: ${arguments.length}`);
}
foo(1);
// rest의 개수: 0
// arguments의 개수: 1
- 나머지 매개변수는
Array
객체이지만,arguments
는 유사 배열 객체이다. - 화살표 함수는 나머지 매개변수는 사용할 수 있지만
arguments
객체를 사용할 수 없다.
자바스크립트는 값에 의한 호출(call by value)을 사용한다. 호출자(caller; 함수를 호출한 전역 또는 함수 문맥)는 함수를 호출할 때 인자를 전달하고, 인자는 값에 의한 호출에 따라 복사된 값으로서 매개변수로 전달된다.
호출된 함수(callee)가 내부에서 전달받은 인수의 값을 바꾸어도 이는 호출자의 문맥에 반영되지 않는다. 그러나 전달된 값이 객체 참조라면, 객체 참조는 값이지만 호출된 함수가 참조된 객체의 프로퍼티를 바꾸면 이 변화는 함수 바깥 곧 호출자에도 반영된다.
따라서 의미를 더 명확히 하기 위해 **공유에 의한 호출(call by sharing)**이라고도 한다. Call by Sharing을 참고한다.
자바스크립트 엔진은 모든 선언문을 런타임 이전에 실행한다. 따라서 함수 선언문 역시 스크립트의 최상단으로 끌어올려지나, 함수 표현식의 경우 변수 선언 부분만 상단으로 끌어올려지고 할당 부분은 런타임에 평가된다. 즉, 함수 선언문으로 정의한 함수의 생성 시점은 런타임 이전이고 함수 표현식으로 정의한 함수의 생성 시점은 런타임으로 서로 다르다.
console.log(foo); // ƒ foo() { console.log('foo'); }
foo(); // 'foo'
function foo() { console.log('foo'); };
console.log(foo); // undefined
foo(); // TypeError: foo is not a function
var foo = function() { console.log('foo'); };
Hoisting을 참고한다.
function foo() {
const x = 1;
function bar() {
console.log(x);
}
return bar;
}
const baz = foo();
baz(); // 1
어떤 중첩 함수에 대하여 이 중첩 함수가 외부 함수보다 더 오래 유지되며, 중첩 함수가 외부 함수의 변수를 참조하는 경우 이 중첩 함수를 클로저(closure)라고 한다.
클로저에 대해서는 Closure를 참고한다.
함수 내부에서 this
의 값은 함수를 호출하는 방식에 따라 달라진다.
함수 호출 방식 | this 가 참조하는 값 |
엄격 모드의 경우 |
---|---|---|
일반 함수로서 호출 | 전역 객체 | undefined |
메서드로서 호출 | 메서드를 호출한 객체 | 메서드를 호출한 객체 |
생성자 함수로서 호출 | 생성자 함수가 생성할 인스턴스 | 생성자 함수가 생성할 인스턴스 |
키워드 this
에 대해서는 this를 참고한다.
- 메서드는 ES6 메서드 축약 표현으로 정의한 함수이다. 메서드는 객체 이니셜라이저나 클래스에서 사용할 수 있다.
- 메서드는 내부에서
super
키워드를 사용하여 바인딩된 객체의 프로토타입 객체의 프로토타입 메서드를 참조할 수 있다.
메서드는 [[HomeObject]]
내부 슬롯으로 자신을 바인딩하고 있는 객체를 참조한다. super
는 이 값([[HomeObject]].__proto__
)을 이용하여 프로토타입 객체에 접근한다.
class Parent {
constructor(name) {
this.name = name;
}
hello() {
return this.name;
}
}
class Child extends Parent {
hello() {
return `${super.hello()}, hello!`;
}
}
console.log(new Child('World').hello()); // World, Hello!
위 Child.prototype.hello
의 [[HomeObject]]
는 Child.prototype
이며, Child.prototype.__proto__
를 통해 Parent.prototype
을 찾을 수 있다. 최종적으로 super.hello
는 Parent.prototype.hello
를 가리킨다.
const foo = {
name: 'foo',
hello() { return this.name; },
};
const bar = {
__proto__: foo,
hello() { return `${super.hello()}, hello!`; },
}
console.log(bar.hello()); // foo, hello!
메서드는 메서드 축약 표현으로 정의된 함수이므로, 클래스에 정의된 메서드뿐만 아니라 객체 리터럴에 정의된 메서드도 [[HomeObject]]
를 가지며 super
를 참조할 수 있다.
함수 선언문과 함수 표현식, Function
생성자, 화살표 함수식로 정의한 경우를 비교한다.
- 함수 표현식과 함수 선언문으로 정의된 함수는 클로저를 생성한다.
Function
생성자로 정의한 함수는 클로저를 생성하지 않는다.
- 함수 표현식과 함수 선언문으로 정의된 함수는 함수를 호출할 때 구문 분석된다.
Function
생성자로 정의한 함수는 생성될 때 구문 분석된다.
??
??
함수 호이스팅을 참고한다.
- 함수 선언문은 함수 선언 이전에 호출할 수 있다. 함수 선언문이 호이스팅되고 실행되어 런타임 이전에 함수 객체를 생성하기 때문이다
- 함수 표현식과
Function
생성자, 화살표 함수식으로 선언한 함수는 선언 이전에 호출할 수 없다. 식별자 선언문만 호이스팅되고 실행되므로 런타임 이전에 함수 객체가 생성되지 않기 때문이다.
**즉시 실행 함수(IIFE; immediately invoked function expression)**는 정의한 즉시 호출되는 함수를 의미한다.
(function(){
console.log('hello world')
})(); // hello world
일반적으로 익명 함수를 즉시 실행 함수로 사용한다.
**재귀 함수(recursive function)**는 자기 자신을 호출하는 **재귀 호출(recursive call)**을 수행하는 함수이다.
function factorial(n) {
if (n <= 1) return 1;
return factorial(n - 1) * n;
}
ES6 이후 함수는 문이 위치할 수 있는 문맥이라면 어디서든 정의할 수 있다. 블록 내부에 정의된 함수는 **블록 레벨 함수(block-level function)**이라고 하며, 블록 레벨 함수의 범위는 해당 블록이다.
'use strict'
function foo () { return 1; }
{
function foo() { return 2; }
}
foo(); // return 1
ES6 이전에는 함수 선언문은 코드의 최상위 또는 다른 함수 내부에서만 정의할 수 있었다. 따라서 다음과 같이 하는 것이 안전했다.
var foo;
{
foo = function() { return 1; }
}
함수 내부에 정의된 함수는 중첩 함수(nested function) 또는 **내부 함수(inner function)**이라 한다. 중첩 함수를 포함하는 함수는 **외부 함수(inner function)**이다. 중첩 함수는 외부 함수 내부에서만 참조할 수 있다.
function outer(x) {
function inner(x) { return x * x; }
console.log(inner(x));
}
outer(2); // 4
**콜백 함수(callback function)**은 어떤 함수의 인수로 전달된 후, 나중에 호출(called back)되는 함수를 의미한다. 익명 함수는 콜백 함수로 많이 사용된다.
button.addEventListener('click', function(event) {
console.log('클릭!')
})
함수형 프로그래밍에서 인자로 다른 함수를 전달받거나 함수를 반환하는 함수를 고차 함수(HOF; higher-order function)라 한다. 콜백 함수를 인자로 받는 함수 역시 고차 함수에 속하며, 콜백 함수는 고차 함수에 의해 호출되고 고차 함수는 콜백 함수를 호출한다.
함수형 프로그래밍에서 외부 상태에 의존하거나 외부 상태를 변경하는 함수를 **부수 효과(side effect)**가 있다고 한다. 이때 부수 효과가 없는 함수는 **순수 함수(pure function)**이라고 한다.
순수 함수는 동일한 인수에 대해 언제나 동일한 값을 반환한다. 어떤 외부 상태에도 의존하지 않고 전달된 인수에만 의존하기 때문이다. 또한 외부 상태를 변경하지 않으므로 인수를 변경하지 않아 인수의 불변성을 유지한다.
function increment(n) {
return n + 1;
}
const num = 1;
increment(num); // 2
console.log(num); // 1
함수가 외부 상태를 변경하면 상태의 변화를 추적하기 어려워지므로 순수 함수를 사용하여 데이터의 불변성을 유지하도록 하는 것이 좋다.
- 모던 자바스크립트 Deep Dive - 12장 함수
- 모던 자바스크립트 Deep Dive - 17장 생상자 함수에 의한 객체 생성
- MDN - Functions