Q. javascript에서 higher-order function에 대해서 알려주세요

존버어 2019. 02. 02. 조회수 707


javascript에서 higher-order function에 대해서 알려주세요.

눈으로 봐서는 잘 이해가 안가네요

공유하고 보상받기 ♥︎
댓글 0

3개의 답변이 있습니다.

질문자 & 큐레이터 채택
비매스터 답변자인증
OpenSG 수석 컨설턴트 2019. 02. 03 75%의 채택

고차함수는 앞서 말씀하신 분처럼 함수를 인자로 전달하거나 함수를 리턴할 수 있는 함수를 말합니다. 또는 둘다 할수도 있구요.

문제는 이걸 왜 사용하느냐일텐데 일단 간단하게만 말씀드리자면 순수함수(pure function)을 이용해 불변성(immutability)을 지향하도록 하는 함수형 프로그래밍이 목적이라고 말할 수 있습니다. 순수함수는 입력 인자가 동일하다면 동일한 결과를 리턴하는 함수를 말합니다. 입력 인자 이외의 외부 요소에 의해 리턴값이 달라지지 않아야 합니다.

고차함수는 순수함수와 이를 보조하는 보조함수를 이용해 함수 내부의 연산에 존재하는 조건문, 반복문을 최대한 제거하여 애플리케이션의 복잡성을 낮추려는데 목적이 있습니다.

Array에서 특정한 조건에 부합되는 데이터만으로 새로운 배열을 만들어내기 위해 filter라는 메서드를 사용하곤 합니다. 다음과 같이 말이죠.

var persons = [
    { name:"홍길동", region:"서울" },
    { name:"이몽룡", region:"제주" },
    { name:"박문수", region:"서울" },
    { name:"변학도", region:"경기" },
    { name:"성춘향", region:"서울" }
]

var seouls = persons.filter(function(p) {
    return p.region === "서울";
})
//var seouls = persons.filter((p)=>p.region==="서울")

console.log(seouls === persons)     //false
console.log(persons);    //홍길동, 박문수, 성춘향

위의 코드에서 filter() 가 바로 고차함수입니다. 이 함수에 전달하는 function(p) { return p.region==="서울"; } 가 바로 보조함수입니다.

이 코드에는 반복문이나 if문이 없습니다. filter 메서드 내부에는 if, for 문이 있겠지만 개발자가 사용할 때는 반복문이 없지요. 또한 seouls 배열과 persons 배열은 다른 것입니다. 기존 배열을 바탕으로 새로운 배열을 만들어냈지요. 이것을 불변성이라고 부릅니다.

함수가 함수를 리턴할 때도 고차함수라고 부릅니다.

var test1 = function(a) {
    return function(b) {
        return a+b;
    }
}

var f1 = test1(10)
console.log(f1(20))         //30
console.log(f1(100))        //110

위의 코드에서 test1(10)으로 호출했을 때 a는 10으로 설정된 함수 호출객체 내부에서 내부함수가 정의되어 리턴돕니다. f1은 바로 그 내부함수입니다. 이것을 여러번 반복적으로 이용할 때 저장된 a를 지속적으로 이용할 수 있습니다.일종의 캐쉬가 일어나죠.. 그래서 비슷한 로직의 실행이 많은 경우 코드의 재사용성이 좋아집니다.

심지어 여기에 함수를 인자로 전달할 수 있습니다.

var test1 = function(fn) {
    return function(a) {
        return function(b) {
            return fn(a,b);
        }
    }
}
//화살표 함수를 쓰시면 이렇게 간단해집니다.
//var test2 = fn => a => b => fn(a,b);

var multiply = test1((x,y)=>x*y)
var multi_base10 = multiply(10);
console.log(multi_base10(20));  //200
console.log(multi_base10(30));  //300

첫번째 test1 함수에 전달한 함수는 test1 함수로 무슨일을 할지 결정을 합니다. 그 이후에 10을 전달하는 것은 10을 기반으로 곱셉을 하겠다는 것을 의미하죠. 그 이후에 20, 30을 전달하는 것은 곱셉, 10은 결정된 함수를 이용해 나머지 인자만 전달하여 연산처리합니다.

이런 기법을 currying 이라고 합니다. 아마 currying 기법중 가장 간단한 예제일 것 같네요..더 자세한 내용은 '자바스크립트 커링'이라는 키워드로 검색해보세요.


또 한가지 고차함수의 목적 중의 하나는 컴포넌트의 재사용성을 높이려는 것입니다. React Component는 Class, Function 유형으로 만들 수 있는데, 어차피 Javascript Class는 내부적으로 function입니다.

class Person { }
console.log(typeof(Person));    //function

고차함수, 고차 컴포넌트는 사실상 같은 의미로 볼수 있지요. React에서는 고차 컴포넌트를 이용해 컴포넌트에 특정 기능을 추가합니다. 상속이라는 개념을 대신해서 컴포넌트에 기능을 확장하는 기법으로도 사용되고 있다는 뜻입니다.

React에서 Drag & Drop 기능을 제공하는 대표적인 라이브러리가 React DnD인데 이것은 고차 함수, 고차 컴포넌트로 이루어져 있습니다. React DnD의 공식 문서의 예제를 적어보면...

// Let's make <Card text='Write the docs' /> draggable!

import React from 'react';
import { DragSource } from 'react-dnd';
import { ItemTypes } from './Constants';

/**
 * Implements the drag source contract.
 */
const cardSource = {
  beginDrag(props) {
    return {
      text: props.text
    };
  }
};

/**
 * Specifies the props to inject into your component.
 */
function collect(connect, monitor) {
  return {
    connectDragSource: connect.dragSource(),
    isDragging: monitor.isDragging()
  };
}

function Card({ isDragging, connectDragSource, text }) {
  return connectDragSource(
    <div style={{ opacity: isDragging ? 0.5 : 1 }}>
      {text}
    </div>
  );
}

// Export the wrapped component:
export default DragSource(ItemTypes.CARD, cardSource, collect)(Card);

Card 컴포넌트는 일반적인 Presentational COmponent입니다. 여기에 Drag 기능을 부여하기 위해 마지막줄의 코드를 작성하고 있죠. DragSource에 수행할 기능이 담긴 함수와 객체를 인자로 전달하고 마지막에 기능을 적용할 컴포넌트(Card)를 지정하면 Drag 가 가능한 새로운 컴포넌트가 리턴됩니다.

이와 유사한 예제로 React 에서 주로 사용되는 Redux라는 상태관리 라이브러리에사 주로 사용되는 react-redux라는 라이브러리도 있습니다. react-redux의 connect라는 함수가 고차함수인데, Redux의 state와 action creator 기능을 컴포넌트에 연결하여 props로 state, action creator가 주입된 컴포넌트를 만들어냅니다.

import React from 'react';
import { connect } from 'react-redux';
import Profile from './components/Profile';

function ProfileContainer(props) {
  return (
    props.loggedIn
      ? <Profile profile={props.profile} />
      : <div>Please login to view profile.</div>
  )
}

const mapStateToProps = function(state) {
  return {
    profile: state.user.profile,
    loggedIn: state.auth.loggedIn
  }
}

export default connect(mapStateToProps)(ProfileContainer);

위의 예제에서 마지막줄의 connect가 고차함수입니다. 주입시킬 state와 props를 연결할 정보와 컴포넌트를 결합하면 호출하면 새로운 컴포넌트를 리턴합니다.

이 앱의 한정된 에디터 공간으로 설명드리기가 참 힘드네요. 그래서 답변을 미루고 있었는데... 잘 정리해서 답변드리지 못해 죄송합니다. 이제부터 추가적인 내용은 본인이 찾아보도록 하세요. 다음의 키워드로요.

  • 함수형 프로그래밍

  • currying

댓글 0
봉으니 답변자인증
시스템 2019. 02. 03 22%의 채택

함수를 인수로 받는 함수, 또는 함수를 반환하는 함수를 일러 고차 함수(higher-order function)라고 합니다.

// 함수를 인수로 받는 함수
function func2(f) {
  f();
}

// 함수를 반환하는 함수
function func1() {
  return function() {};
}
댓글 0
오호랏 답변자인증
지갑팀 2019. 02. 03 3%의 채택

사실 개념은 봉으니님 답변이 전부라 할수 있습니다.

고차함수 개념은 최근 많은 언어에서 적용하고 있으니 제대로 이해하시면 좋겠습니다.

다음은 자바스크리트의 함수형 프로그래밍 개념을 예제와 함께 설명한 곳입니다. 차근차근 읽어 보시길 바랍니다.

http://reactivex.io/learnrx/

댓글 0