Section2 / Unit1 : JS 고차함수
코드스테이츠 수업 21일 차!
어느덧 한 달이 지나고 섹션2에 들어왔는데 어제 한 달 회고하면서 굳건히 다졌던 마음이 하루만에 무너질 뻔했다. 너무 어려웠다🫠
어제 다잡았던 마음을 벌써 까먹지 않기 위해 다시 회상해보자.
다른 분들의 열정 가득한 회고를 보니 무너졌던 멘탈에 아주 큰 동기부여가 됐다.
모두가 열심히 하고 있고 스스로와 싸우며 이겨내려 노력하고 있었다.
뒤쳐지지 않게 공부하자.
개념이 바로바로 인지가 안 되는 것 같으니 블로깅 하면서 다시 복습해야겠다. 될 때까지 가보자고
학습목표
- 일급 객체(first-class citizen)의 3가지 특징을 설명할 수 있다.
- 고차 함수(higher-order function)에 대해 설명할 수 있다.
- 고차 함수를 자바스크립트로 작성할 수 있다.
일급 객체의 특징
- JavaScript의 대표적인 일급 객체 중 하나가 함수
- 변수에 할당할 수 있다.
- 다른 함수의 전달인자로 전달될 수 있다.
- 다른 함수의 결과로써 리턴될 수 있다.
//변수에 함수를 할당하는 경우
//함수 표현식은 변수에 할당한 다음 사용할 수 있습니다.
const square = function(num){
return num * num;
}
output = square(7);
console.log(output); //49
고차 함수(higher order function)
- 함수를 전달인자로 받을 수 있고, 함수를 리턴할 수 있는 함수
- 함수는 변수에 저장할 수 있다.
- 함수를 담은 변수를 전달인자로 받을 수 있다.
- 함수 내부에서 변수에 함수를 할당할 수 있다.
그리고 함수는 이 변수를 리턴할 수 있다.
여기서 변수에 할당하지 않고 함수를 바로 이용할 수 있다. - 어떤 고차 함수에 함수를 전달인자로 전달하고, 고차 함수는 함수 자체를 리턴한다.
- 콜백 함수(callback function) : 다른 함수의 전달인자로 전달되는 함수
- 콜백 함수를 전달받은 고차 함수는, 함수 내부에서 이 콜백 함수를 호출할 수 있고,
조건에 따라 콜백 함수의 실행 여부를 결정할 수도 있다. - 커링 함수 : 함수를 리턴하는 함수
- 고차 함수가 커링 함수를 포함한다.
//다른 함수를 인자로 받는 경우
function double(num){
return num * 2;
}
function doubleNum(func, num){
return func(num);
}
//아래 경우, double은 doubleNum의 콜백 함수
let output = doubleNum(double, 4);
console.log(output); // 8
//함수를 리턴하는 경우
function adder(added){
return function(num){
return num + added;
}
}
let output = adder(5)(3);
console.log(output); // 8
//함수는 일급 객체이기 때문에 adder가 리턴하는 함수를 변수에 저장할 수 있다.
const add3 = adder(3);
output = add3(2);
console.log(output); // 5
//함수를 인자로 받고, 함수를 리턴하는 경우
function double(num){
return num * 2;
}
function doubleAdder(added, func){
const doubled = fun(added);
return function(num){
return num + doubled;
}
}
//doubleAdder의 인자 func는 함수 doubleAdder의 콜백 함수입니다.
//함수 double은 함수 doubleAdder의 콜백으로 전달되었습니다.
//doubleAdder(5, double)는 함수
doubleAdder(5, double)(3); // 13
//doubleAdder가 리턴하는 함수를 변수에 저장할 수 있다.
const addTwice3 = doubleAdder(3, double);
addTwice3(2); // 8
학습목표
- 추상화에 대해 설명할 수 있다.
- 추상화의 관점에서 고차 함수가 갖는 이점에 대해 설명할 수 있다.
- 고차 함수를 통해 사고 수준에서의 추상화를 달성할 수 있다.
추상화
- 복잡한 어떤 것을 압축해서 핵심만 추출한 상태로 만드는 것
- 생산성(productivity)의 향상
- 추상화 관점에서, 함수는 사고(thought) 또논 논리(logic)의 묶음
- 함수를 통해 얻은 추상화를, 한 단계 더 높인 것이 고차 함수
- 함수 = 값을 전달받아 값을 리턴한다. = 값에 대한 복잡한 로직은 감추어져 있다 = 값 수준에서의 추상화
- 값 수준의 추상화 : 단순히 값을 전달받아 처리하는 수준
- 사고의 추상화 : 함수(사고의 묶음)를 전달받아 처리하는 수준
- 고차 함수 = 함수를 전달받거나 함수를 리턴한다 = 사고(함수)에 대한 복잡한 로직은 감추어져 있다 = 사고 수준에서의 추상화
코플릿 고차함수 오답노트
17번
<문제>
수를 요소로 갖는 배열을 입력받아 각 요소가 2의 배수인지에 대한 정보를 요소로 갖는 새로운 배열을 리턴해야 합니다.
통과 안 된 코드
// 전체 통과 X
function checkEvenOrNot(arr) {
// TODO: 여기에 코드를 작성합니다.
const newArr = function(el){
if(el%2 === 0) return 'ok'
else if(el === 0) return 'no'
else return 'no'
}
return arr.map(newArr)
}
통과된 코드
// 전체 통과 O
function checkEvenOrNot(arr) {
// TODO: 여기에 코드를 작성합니다.
const newArr = function(el){
if(el%2 !== 0) return 'no'
else if(el === 0) return 'no'
else return 'ok'
}
return arr.map(newArr)
}
조건문은 거름망이라고 생각하면 된다고 했다. 아래로 내려갈 수록 세분화 된다고
그래서
if(el%2 === 0) return 'ok'
else if(el === 0) return 'no' 이 구문에서
0도 0%2 는 0이므로 'no'가 안 먹히는 거였다
따라서 아래코드처럼 순서를 바꾸면 해결된다.
function checkEvenOrNot(arr) {
// TODO: 여기에 코드를 작성합니다.
const newArr = function(el){
if (el === 0) return 'no'
else if(el%2 === 0) return 'ok'
else return 'no'
}
return arr.map(newArr)
}
20번
<문제>
객체와 키를 입력받아 키에 해당하는 값이 배열인 경우, 배열의 각 요소를 제곱한 새로운 배열을 리턴해야 합니다.
통과 안 된 코드
function square(number) {
return number * number;
}
function getSquaredElementsAtProperty(obj, property) {
// TODO: 여기에 코드를 작성합니다.
if(Array.isArray(obj.property)){
return obj.property.map(square);
}
return [];
}
통과 된 코드
function square(number) {
return number * number;
}
function getSquaredElementsAtProperty(obj, property) {
// TODO: 여기에 코드를 작성합니다.
if(Array.isArray(obj[property])){
return obj[property].map(square);
}
return [];
}
obj.property 와 obj[property]의 차이인데 아직 개념이 덜 인지돼서 그런지 헷갈렸다
property는 변수이므로 []를 사용해서 집어넣어야 한다.
obj.key는 객체의 속성 키가 문자열일 때 사용하는 구문, 객체에서 속성 이름이 고정된 경우에만 사용
obj[key]는 객체의 속성이름이 동적으로 사용될 때 사용
그리고 return []; 을 사용한 이유는
property 속성이 존재하지 않거나 배열이 아닌 경우 빈 배열을 반환,
함수의 반환 값이 항상 배열 형태이기 위해 사용
21번
<문제>
개인 정보를 담고 있는 객체를 요소로 갖는 배열을 입력받아 18세 이상인 사람의 이름을 요소로 갖는 배열을 리턴해야 합니다.
통과 안 된 코드
function getOnlyAllowedToDrink(arr) {
// TODO: 여기에 코드를 작성합니다.
const arrAge = arr.filter(function(person){
return person[age] >= 18
})
const arrName = arrAge.map(function(person){
return person[name];
})
return arrName;
}
통과 된 코드
function getOnlyAllowedToDrink(arr) {
// TODO: 여기에 코드를 작성합니다.
const arrAge = arr.filter(function(person){
return person.age >= 18
})
const arrName = arrAge.map(function(person){
return person.name;
})
return arrName;
}
20번과 비슷한 상황이다
person[age]와 person[name]은 변수 age와 name을 찾으려고 시도하지만
정의되어 있지 않은 변수들이므로 ReferenceError를 발생시킨다
person.age와 person.name은 age와 name 대신 person 객체의 age와 name 속성에 직접 접근한다
따라서 이 방식이 올바르다
27번
<문제>
문자열을 요소로 갖는 배열을 입력받아 배열에서 가장 긴 문자열을 리턴해야 합니다.
나도 통과한 코드기는 한데 효재님 코드가 더 짧고 간결하게 표현하셨다
//내 코드
function getLongestElement(arr) {
// TODO: 여기에 코드를 작성합니다.
return arr.reduce(function (a, b){
if(a.length >= b.length){
return a
}else{
return b
}
},'')
}
//효재님 코드
function getLongestElement(arr) {
return arr.reduce((acc, cur) => acc.length < cur.length ? cur : acc, '')
}
코드를 간결하게 표현하기 위해 노력하자