LearningJavaScript

15. 고차함수

jyshimmy 2020. 8. 14. 18:47

일급 시민 (first-class citizen)

일급 시민의 조건(특징):

  • 변수 안에 담을 수 있다 즉, 변수에 할당(assign) 할 수 있다
  • 다른 함수(또는 메소드)의 인자(argument)로 전달 될 수 있다
  • 반환(return) 값으로 사용할 수 있다

대부분의 프로그래밍 언어에서 숫나자 문자는 1급 시민의 조건을 충족시킨다. 그리고 자바스크립트에서 객체 또한 위의 조건을 충족시키기 때문에 일급 객체가 되고, 자바스크립트 함수는 객체를 상속받기 때문에 일급 함수가 된다.

 

자바스크립트 객체 속성을 보여주는 console.dir을 함수도 사용할 수 있다는 사실 자체가 함수가 객체임을 대변해주지만, 상위 객체를 가르키는 __proto__에 "Object" 가 있음을 확인 할 수 있다.

함수를 변수에 저장하여 사용하는 법을 함수 표현식(function expression), 그리고

 

**hoisting is JavaScript's default behavior of moving all declarations to the top of the current scope (to the top of the current script of the current function). Variables and constants declared with let or const are not hoisted. JavaScript only hoists declarations, not initializations.

여기에 대해선 조금 더 공부가 필요!

 

함수 표현식 vs. 함수 선언식

//함수 선언식
function myHello(){
  console.log("hello");
}

//함수 표현식
let myFunc = function() { //함수에 이름이 없는 "익명함수"
  console.log("@@@");
}

함수 표현식은 변수에 함수명을 선언과 동시에 (익명)함수를 할당한다.

추가해보자면, 변수 myFunc는 함수가 아니라 익명함수를 가르키고 있을 뿐이다.

그렇다면 함수 선언식과 함수 표현식은 각각 언제 쓰이는가, 어떻게 쓰이면 좋은가? (자신에게 묻는 질문 29Sep20)

  특징
함수 선언식 - 함수가 선언되는 위치와 관계없이 실행될 수 있다. (호이스팅 - 브라우저가 자바스크립트를 해석할 때 함수가 맨 위로 끌어 올려지는 현상)
함수 표현식 - 변수에 저장된 함수는 다른 함수의 인자 또는 다른 함수내에서 리턴 값으로 전달 될 수 있다. (고차함수 - 콜백이 가능)
- 호이스팅이 불가하기 때문에 함수가 할당되는 위치와 실행 되는 위치가 중요하고, 따라서 코드를 리뷰 또는 디버깅 할 때 코드의 위치가 어느정도 예측이 가능하다.
- 클로져로 사용 가능

 

**변수의 값을 찾을 때 확인 하는 곳이 "scope"; 함수가 정의된 상태에서 함수 이름을 콘솔에 쓰면, 

invoke operator: ()

이것은 무얼 말하려고 했던가? 

 

위의 내용을 정리하면,

....고차함수

고차함수 (higher-order function; HoF)

고차 함수는 자신 외, 다른 함수를 인자(argument)로 받거나 다른 함수를 리턴하거나 둘 다 한다. 이 때 다른 함수 (caller)의 인자 (argument)로 전달되는 함수를 콜백 함수(callback function)라고 한다. 각각의 경우에 대해 살펴보자.

 

Case1. 다른 함수를 인자로 받는 경우 (콜백함수)

function double(num) {
  return num * 2;
}

function doubleNum(func, num) { // 여기서 func는 아직 콜백함수라고 할 수 없다
  return func(num);
}

let doubled = doubleNum(double, 4); // 여기서 func는 doubleNum의 콜백함수다
console.log(doubled); // -> 8

위에서 doubleNum 함수가 처음 선언되었을 때, func 매개변수는 콜백함수의 자리를 나타내고 있다. 후에 doubled 에서 double이 인자로 들어와서야 콜백 함수가 된다.

 

Case2. 함수를 리턴하는 경우

function adder(added) {
  return function(num) {
  return num + added;
  };
}

const output = adder(5)(3);
console.log(output); // 8

const add3 = adder(3);
output = add3(2);
console.log(output); // 5

함수 adder는 인자 added를 입력받고, 익명 함수인 function(num)을 리턴하는 고차함수다.

여기서 adder(3)가 리턴하는 함수((function(num))를 변수 add3에 저장할 수 있는 이유는 JS에서 함수가 일급 객체이기 때문에 가능하다. 따라서 add3(2)는 function(num)의 인자로 들어갈 수 있다. 

 

Case3. 함수를 인자로 받고, 함수를 리턴하는 경우

function double(num) {
  return num * 2;
}

function doubleAdder(added, func) {
  const doubled = func(added);
  return function (num) {
    return num + doubled;
  };
}

doubleAdder(5, double)(3); // 13; added(함수 doulbe에서의 num이다) === 5, num === 3

const addTwice3 = doubleAdder(3, double);
addTwice3(2); // 8; added === 3, num ===2

위에서 doubleAdder는 콜백 함수 double을 인자로 받고, 익명 함수인 function(num)을 리턴하는 고차함수다.

사실, 맨 위 Case1.에서도 "return func(num)"에서도 func가 콜백 "함수"라 함수를 리턴하는 것이 아닌가 잠시 헷갈렸지만, 여기서 func(num)은 고차 함수내에서 실행되지않고 이미 실행되어 그 리턴값만 있다고 볼 수 있다.

doubleAdder(5, double)은 함수이기때문에 ()기호를 이용해 함수를 호출될 수 있다.

 

 

내장 고차 함수 이해하기

자바스크립트는 기본적으로 내장(built-in)되어 있는 고차 함수들이 있다. 배열 메소드 중 일부가 이에 해당된다.

"다른 메소드와 내장 메소드를 구분할 수 있는 가장 쉬운 방법은 MDN에서 메소드를 검색했을 때 메소드가 Array.prototype.filter()처럼 프로토타입으로 나오는지 여부다." - 확인 필요!(30Sep20)

 

배열 메소드 활용

filter method

배열의 필터 메소드는 배열의 요소들 중 특정 조건에 만족하는 요소들만 걸러내준다, 혹은 필터해준다. 아래 예시의 경우엔 문자열을 요소로 갖고 있는 배열이 있고, 여기서 필터 메소드를 사용해 문자열의 길이가 4를 초과하는 요소들만 걸래내는 고차 함수를 보여준다.

const isLongerThan4 = function(string) {
  return string.length > 4;
}

const filterByLength = function(array, filtering) { // 여기서 filtering은 콜백함수를 전달받을 매개변수다
  return array.filter(filtering);
}

const arr = ['hello', 'world', 'happy', 'coding', 'life'];

이때 중요한 점은 기존 배열은 변하지 않는다는 점이다. 따라서 filterByLength 함수를 실행한뒤에도 콘솔로그에 arr을 찍으면 기존 배열이 그대로 유지되고 있음을 볼 수 있다.

필터 메소드의 syntax는 아래와 같다.

let newArray = arr.filter(callback(element));

여기서 element는 필터 처리 대상인 배열(arr)의 요소이고, callback은 인자로 받는 element, 즉 배열의 각 요소를 모두 특정 조건에 대입 시킨 후, 리턴 값이 참인 값만 갖고, 거짓인 값은 생략하는 함수다. 이 때, 필터 메소드의 리턴 값을 갖는 newArray는 변수명에서 힌트를 얻을 수 있듯, 기존 배열에서 필터 조건을 충족시키는 요소들로만 구성된 새로운 배열이 된다는 점을 꼭 기억하자!!!

 

filter(callback(el)) 예 찾아보기!!!!

reduce method

[1,2,3,4].reduce(function callback(acc, ele) {
console.log(`누적된 값: ${acc}, 으앗: ${ele}`)
return acc
}, 0)

 

 

고차 함수 활용

**mdn에서 []안에 있는 애들은 optional, they are optional!

추상화 (abstraction) - 추상화의 관점에서 고차함수가 갖는 이점