March 20, 2021
const add10 = function(a) { // 함수를 변수에 담을 수 있다.
return 10 + a;
}
function apply(arr, op) {
return arr.map(op);
}
apply([1,2,3], add10); // 함수를 매개변수로 전달할 수 있다.
function makeAdd(v1) {
return function(v2) { // 함수 안에서 또 다른 함수를 반환할 수 있다.
return v1 + v2;
}
}
const add3 = makeAdd(3); // 반환된 함수를 변수에 할당하여 사용할 수 있다.
console.log(add3(10)); // 13
const add7 = makeAdd(7);
console.log(add7(10)); // 17
function makeAdd(v1) {
return function(v2) {
return v1 + v2;
}
}
const add3 = makeAdd(3);
console.log(add3(10)); // 13
makeAdd(3)
: makeAdd
함수를 호출할 때 매개변수로 3
을 전달했기 때문에 이 때 v1
은 3
이 되고 이 함수는 또 다른 함수를 반환하고 실행을 끝낸다.
add3
변수에는 함수가 할당되고 그 아래 행에서 add3
에 할당된 함수를 실행한다.
function(v2) {
return v1 + v2;
}
이 때 v1
을 사용하고 있다.
이 v1
은 이전에 실행했던 함수에서 사용했던 매개변수이다. 클로저가 없었다면 makeAdd(3)
함수가 호출되고 실행을 종료하면서 v1
은 사라졌을텐데 클로저 덕분에 add3
함수를 실행할 때에도 v1
값을 사용할 수 있는 것이다.
Example
function f1() {
const v1 = 123;
console.log(v1); // 123
}
const v2 = 456;
function f2() {
f1();
console.log(v2); // 456
}
f2();
f2()
함수 실행을 만난다. 그러면 지금까지 갖고있던 현재의 global execution context를 콜 스택에 넣는다. f2()
함수 호출을 위한 새로운 execution context가 생성된다.f2
함수 내부 로직이 실행된다.f1()
: 또 다른 함수의 실행을 만난다.f1()
함수 호출을 위한 새로운 execution context가 생성된다.f1
함수 내부 로직이 실행된다.v1: 123
이라는 정보를 가지고 있다.console.log(v1)
: v1
변수가 사용될 때 먼저 lexical environment에서 찾는다.f1
함수의 실행이 끝나고 현재 갖고 있는 execution context는 삭제된다. 콜스택에서 마지막에 저장된 것을 하나 꺼내온다. 그러면 이전에 f1
함수실행한 부분 그 다음부터 다시 실행을 한다.console.log(v2)
로 v2
를 찾으려고 하는데 v2
가 없다.
이 경우, 글로벌 영역에서 456
을 가져오는데, 이는 함수가 생성될 때 부모 함수의 lexical environment를 기억하기 때문이다. 그리고 그 함수가 호출될 때 부모 함수의 lexical environment를 체인으로 연결한다.f2
함수의 실행이 끝나고 현재 갖고 있는 execution context는 삭제하고 콜스택에 담겨있는 execution context를 하나 꺼내온다. (global execution context) 그러면 이전에 f2
함수를 실행한 부분 그 다음부터 다시 실행을 한다. v2
변수가 있다. global execution context 안에 있는 lexical environment에 v2: 456
이라는 값이 있는 것이다.function printLog(a = 1) {
console.log({ a });
}
printLog(); // { a: 1 } 기본값이 사용되었다.
printLog(3); // { a: 3 }
function getDefault() {
console.log('called getDefault');
return 1;
}
function printLog(a = getDefault()) {
console.log({ a });
}
printLog(); // { a: 1 } getDefault 함수가 호출되고 기본값 사용되었다.
printLog(3); // { a: 3 } getDefault 함수가 호출되지 않는다.
function required() {
throw new Error('no parameter');
}
function printLog(a = required()) {
console.log({ a });
}
printLog(); // 에러 발생!
printLog(3); // { a: 3 } 정상 출력
function printLog(a, ...rest) {
console.log({ a, rest });
}
printLog(1,2,3); // { a: 1, rest: [ 2, 3 ] }
1
을 제외한 나머지는 rest
라는 매개변수에 배열 형태로 담긴다.function getValues1(numbers, greaterThan, lessThan) {
return numbers.filter(item => greaterThan < item && item < lessThan);
}
function getValues2({numbers, greaterThan, lessThan}) {
return numbers.filter(item => greaterThan < item && item < lessThan);
}
const numbers = [10, 20, 30, 40];
const result1 = getValues1(numbers, 5, 25);
const result2 = getValues2({ numbers, greaterThan: 5, lessThan: 25 });
getValues1
처럼 명명된 매개변수를 사용하지 않을 경우, 각각의 값이 어떤 것을 의미하는지 알기 힘들다.getValues2
처럼 명명된 매개변수를 사용할 경우, 각각의 값이 어떤 것을 의미하는지 알기 쉽다.getValues(numbers, undefined, 25)
이런식으로 중간에 undefined
를 입력해야 한다.getValues({ numbers, lessThan: 25 })
이런식으로 입력하고 싶은 매개변수만 입력할 수 있다.const add = (a, b) => a + b;
const add5 = a => a + 5;
const addAndReturnObject = (a, b) => ({ result: a + b });
const add = (a, b) => {
if (a <= 0 || b <= 0) {
throw new Error('must be positive number');
}
return a + b;
}
function Counter() {
this.value = 0;
this.add = amount => {
this.value += amount;
}
}
const counter = new Counter();
console.log(counter.value); // 0
counter.add(5);
console.log(counter.value); // 5
const add2 = counter.add;
add2(5);
console.log(counter.value); // 10
new Counter()
new
키워드를 이용하여 인스턴스를 생성한다.counter
객체가 생성되는 것.new
키워드를 이용하여 함수를 호출 하면, 함수 안에서 사용된 this
는 counter
객체를 가리키게 된다.counter
객체는 value
와 add
라는 속성을 갖게 된다.this
는 이 화살표 함수가 생성될 당시의 this
를 가리킨다. 즉, 함수 내의 this
는 counter
로 고정되는 정적의 값이다.function Counter() {
this.value = 0;
this.add = function(amount) {
this.value += amount;
}
}
const counter = new Counter();
console.log(counter.value); // 0
counter.add(5);
console.log(counter.value); // 5
const add2 = counter.add;
add2(5);
console.log(counter.value); // 5
this
와 다르게 동작한다.add
함수를 add2
라는 새로운 변수에 할당하고 호출한 다음에 value
를 찍어보면 10
이 찍힐 것 같지만, 5
가 찍힌다. add2(5)
함수가 호출될 때 함수 내에서 this
가 가리키는게 counter
가 아니기 때문이다.일반 함수의 this
는 함수를 호출한 주체를 가리킨다.
counter.add(5)
에서 함수를 호출한 주체는 counter
이기 때문에 함수 내에서 this
는 counter
이다.add2(5)
에서 함수를 호출한 주체는 전역 객체이기 때문에 함수 내에서 this
는 (브라우저 환경에서) window
가 된다.this
가 바뀌기 때문에 동적이다.const counter = {
value: 0,
add: function(amount) {
this.value += amount;
}
};
console.log(counter.value); // 0
counter.add(5);
console.log(counter.value); // 5
const add2 = counter.add;
add2(5);
console.log(counter.value); // 5
0
, 5
, 5
가 출력된다.const counter = {
value: 0,
add: (amount) => {
this.value += amount;
}
};
console.log(counter.value); // 0
counter.add(5);
console.log(counter.value); // 0
const add2 = counter.add;
add2(5);
console.log(counter.value); // 0
0
이 출력된다.this
는 항상 전역 객체를 가리키게 된다. (해당 화살표 함수를 감싸고 있는 일반 함수가 없기 때문에)this.value += amount;
가 아무리 실행이 되어도 counter.value
의 값이 변하지 않는다.