[TIL] Day21 #고차함수 #filter #map #reduce

Beanxx·2022년 5월 24일
0

TIL

목록 보기
21/120
post-thumbnail

[TIL] Day21
[SEB FE] Day21

1️⃣ 고차 함수

함수를 전달인자(argument)로 받을 수 있고, 함수를 리턴할 수 있는 함수

📎 일급 객체

다른 객체들에 일반적으로 적용 가능한 연산을 모두 지원하는 객체

✋ 일급 객체 중 하나가 바로 ‘함수’

  • 변수에 할당 가능 → 함수를 배열 요소나 객체 속성값으로 저장 가능 (함수를 데이터처럼 다룰 수 있음)

    // 변수에 할당 전에 함수 표현식 사용 불가
    // square(5); <- (X)
    
    const square = function (num) {
    	return num * num;
    };
    
    output = square(5);
    console.log(output); // 25
    
    ----------
    
    // 함수는 일급 객체 -> 객체 속성 값으로 할당될 수 있음
    const cat = {
    	name: 'nabi',
    	age: 3,
    	cry: function(){
    	 console.log('miaow...') 
    	}
    }
  • 다른 함수의 전달인자(argument)로 전달될 수 있음

  • 다른 함수의 결과로서 리턴 가능

    ⇒ 문자열, 숫자 같은 다른 데이터처럼 사용 가능!


✔️ 콜백 함수(callback function): 다른 함수(caller)의 전달인자로 전달되는 함수

✔️ 커링 함수: 함수를 리턴하는 함수 (고차 함수 → 함수를 전달인자로 받는 함수에만 한정 사용)

✋ 고차 함수가 커링 함수를 포함 ⇒ 함수 리턴 함수, 함수를 전달인자로 받는 함수 모두 고차 함수로 사용

  1. 다른 함수를 인자로 받는 경우

    function double(num) {
    	return num * 2;
    }
    
    // 다른 함수를 인자로 받는 고차 함수
    // 첫번째 인자 func에 함수가 들어올 경우, 함수 func는 함수 doubleNum의 콜백 함수
    function doubleNum(func, num) {
    	return func(num);
    }
    
    // 함수 double은 함수 doubleNum의 콜백 함수
    let output = doubleNum(double, 5);
    console.log(output); // 10
  2. 함수를 리턴하는 경우

    // 다른 함수를 리턴하는 고차 함수
    function adder(added) {
    	return function (num) { // 익명 함수를 리턴
    		return num + added;
    	};
    }
    
    // adder(3)은 함수이므로 함수 호출 연산자 '()' 사용 가능
    let output = adder(3)(4); // 7
    console.log(output); // 7
    
    // adder가 리턴하는 함수를 변수에 저장 가능
    const add3 = adder(3);
    output = add3(4);
    console.log(output); // 7
  3. 함수를 인자로 받고, 함수를 리턴하는 경우

    function double(num) {
    	return num * 2;
    }
    
    // 고차 함수
    function doubleAdder(added, func) {
    	const doubled = func(added); // 인자 func은 함수 doubleAdder의 콜백 함수
    	return function (num) {
    		return num + doubled;
    	};
    }
    
    // 함수 double은 함수 doubleAdder의 콜백으로 전달
    // doubleAdder(5, double)은 함수이므로 함수 호출 기호 '()' 사용 가능
    doubleAdder(5, double)(6); // 6+(5*2)
    
    // 함수 doubleAdder가 리턴하는 함수를 변수에 저장 가능 => 일급 객체
    const addTwice5 = doubleAdder(5, double);
    addTwice5(6); // 16
// a. 함수를 리턴하고 있으므로 고차함수
function calculate(x, y){
	return function(){
		return x * y;
	}
}

----------

// b. 함수를 전달인자로 받지 않았고, 함수를 리턴하고 있지 않으므로 고차함수 아님!
function calcuate(x, y, z){
	const plus = function (num1, num2){
		return num1 + num2;
	}
	return plus(x, y) * z
}


2️⃣ 내장 고차 함수

✋ 배열 메서드들 중 일부는 고차 함수에 해당

📎 filter method

모든 배열의 요소 중에서 특정 조건을 만족하는 요소를 걸러내는 메서드

  • 배열의 각 요소에 콜백 함수를 적용시켰을 때, true를 리턴하는 요소들만 모은 새로운 배열을 리턴
  • 기존 배열 변경 ❌
  • 걸러내는 기준이 되는 특정 조건(함수 형태)은 filter 메서드의 전달인자로 전달
    - 즉, 조건을 명시한 함수를 전달인자로 받기 때문에 → 고차함수

  1. filter 메서드는 배열의 요소를 콜백 함수에 다시 전달
  2. 콜백 함수는 전달받은 배열의 요소를 받아 함수 실행
// 함수 표현식 (짝수 판별 함수)
const isEven = function (num) {
	return num % 2 === 0;
};

let arr = [1, 2, 3, 4];

// 짝수 판별 함수인 isEven이 조건으로써 filter 메서드의 전달인자로 전달
let output = arr.filter(isEven);
console.log(outpu); // [2, 4]

----------

// 길이 5 이하 판별 함수
// Lte = less than equal
const isLteFive = function (str) {
	return str.length <= 5;
};

arr = ['hi', 'happy', 'coding'];

// 길이 5 이하 판별 함수인 isLteFive가 조건으로써 filter 메서드의 전달인자로 전달
let output = arr.filter(isLteFive);
console.log(isLteFive); // ['happy', 'coding']

📎 map method

배열의 각 요소에 콜백 함수를 적용시킨 새로운 배열을 리턴

  • 기존 배열 수정 ❌

  • 배열의 각 요소가 특정 논리(함수)에 의해 다른 요소로 지정(map)

    let arr = [1, 2, 3];
    
    let result = arr.map(
    function(ele) {
        return ele * 2
    });
    
    result; // [2, 4, 6]

📎 reduce method

배열의 각 요소를 콜백 함수에 맞게 하나로 응축시킨 값을 리턴

  • 초기값을 지정할 수 있음 (지정하지 않으면 배열의 첫번째 요소를 초기값으로 생각)
    • 초기값 지정시 2번째 값은 배열의 첫번째 요소.
    • 초기값 지정시 지정하지 않았을 때 보다 1회 더 실행
  • 배열을 하나의 값으로 만들어줌
  • 배열의 각 요소를 특정 방법(함수)에 따라 원하는 하나의 형태로 응축(reduction)
    • 여러 데이터를 하나의 데이터로 응축(reduce)할 때 reduce를 사용

✋ keyword: 누적값, 초기값, 현재값 !!

    let arr = [1, 2, 3];

    // 초기값 지정 x
    let result = arr.reduce(
    function(acc, cur, idx) {
        acc + cur;
        return acc;
    });

    result; // 6

    ----------

    // 초기값 1로 지정
    let result = arr.reduce(
    function(acc, cur, idx) {
        acc + cur;
        return acc;
    }, 1);

    result; // 7
// 배열 -> 문자열로
// result: 모든 users의 name
let users = [
	{name: 'Tom', age: 10},
	{name: 'Smith', age: 20},
	{name: 'Sam', age: 30}
];

function joinName(resultStr, user) {
	resultStr = resultStr + user.name + ', ';
	return resultStr;
}

users.reduce(joinName, ''); // 'Tom, Smith, Sam,'

----------

// 배열 -> 객체로
// user name 첫글자를 주소록 객체 속성 key로, user 정보를 객체 속성 value로 추가
function makeAddressBook(addressBook, user) {
  let firstLetter = user.name[0];

  if(firstLetter in addressBook) {
    addressBook[firstLetter].push(user);
  } else {
    addressBook[firstLetter] = [];
    addressBook[firstLetter].push(user);
  }

  return addressBook;
}

users.reduce(makeAddressBook, {});

/* 
{
  T: [
    { name: 'Tim', age: 10 }
  ],
  S: [
    { name: 'Smith', age: 20 },
    { name: 'Sam', age: 30 }
  ]
}
*/

✋ 빈 배열을 가지고 reduce 사용시 초기값 0을 지정해야 함 → 안 주면 error

[].reduce(function (acc, cur) {
	return ~~~
}, 0);


3️⃣ 고차 함수의 중요성

📎 추상화(abstraction)

복잡한 어떠한 것을 압축해서 핵심만 추출한 상태로 만드는 것

추상화 = 생산성(productivity)의 향상

  • 자주 반복해서 사용하는 로직은 별도의 함수로 작성 → 추상화의 좋은 사례
  1. 값 수준의 추상화: 단순히 값(value)을 전달받아 처리하는 수준
  2. 사고의 추상화: 함수(사고의 묶음)를 전달받아 처리하는 수준
    a. 고차 함수 = 함수를 전달받거나 함수 리턴 = 사고(함수)에 대한 복잡한 로직은 감추어져 있음 = 사고 수준에서의 추상화

➕ ETC

  • arguments 객체: 함수에 전달된 인수에 해당하는 Array 형태의 객체
function func1(a, b, c) {
  console.log(arguments[0]);  // 1
  console.log(arguments[1]);  // 2
  console.log(arguments[2]);  // 3

}

func1(1, 2, 3);
/*
1
2
3
*/
profile
FE developer

0개의 댓글