함수 & 일급객체

1Hoit·2023년 1월 12일
0

자바스크립트

목록 보기
7/25

함수란?

프로그래밍 언어의 함수는 일련의 과정을 문으로 구현하고 코드 블록으로 감싸서 하나의 실행단위로 정의한 것이다.

함수를 사용하는 이유?

코드의 재사용을 높일 수 있다!


함수 선언문과 표현식

function add(x,y){ return x+y; }; // 함수선언문
const add = function(x,y){ return x+y; }; // 함수 표현식

둘의 차이는 함수 선언문은 함수 호이스팅이 발생,
함수 표현식은 변수 호이스팅이 발생한다.


자바스크립트에서 함수는 일급객체로 취급한다.

일급객체란?

  1. 무명의 리터럴로 생성 가능하다. 즉, 런타임에 생성이 가능하다.
  2. 변수나 자료구조(객체,배열)등에 저장 할 수 있다.
  3. 다른 함수의 전달인자(argument)로 전달될 수 있다.
  4. 다른 함수의 결과로 리턴할 수 있다.

즉, 함수를 변수에 할당할 수 있기 때문에, 함수를 배열의 요소나 객체의 속성값으로 저장할 수 있고 함수를 데이터(string, number, boolean, array, object)처럼 다룰 수 있다.


일반객체? 함수객체? 차이점?

일반 객체와 차이점으로는 일반 객체는 호출할 수 없지만 함수 객체는 호출할 수 있으며 함수 객체 고유의 데이터 프로퍼티(arguments, caller, length, name, prototype)를 소유하며 일반객체의 프로퍼티도 상속받는다.
(일반객체 프로퍼티 = Ojbect.prototype 객체의 프로퍼티로는 __proto__ 접근자 프로퍼티 등이 있다.)

함수 객체가 가진 데이터 프로퍼티

위에서 말한것 처럼 여러개가 있지만 일부만 살펴보자

1. arguments 프로퍼티

arguments 프로퍼티 값은 arguments객체다. 함수 호술 시 전달된 인수들의 정보를 담은 유사 배열 객체이며, 함수 내부에서 지역 변수처럼 사용된다.
만약 인수가 매개변수보다 많다면 arguments 객체에 따로 저장된다.
예시) 가변함수에 유용한 예시

//ES6 문법 Rest파라미터 사용
finction sum6(...args){
	args.reduce((pre,cur)=> pre+cur,0) 
}

//ES5 문법 arguments 객체를 배열로 반환
function sum5(){
	const array = Array.prototype.slice.call(arguments);
  return array.reduce(function(pre,cur){
  return pre+cur;
  },0);
}

console.log(sum5(1,2)) // 3
console.log(sum6(1,2)) // 3

console.log(sum5(1,2,3,4,5)) //15
console.log(sum6(1,2,3,4,5)) //15

2. length 프로퍼티

함수를 정의할 때 선언한 매개변수의 개수를 가리킨다.

function foo(){}
console.log(foo.length); //0

function bar(x,y,z){
	return x+y+z; 
}
console.log(bar.length); //3

단, arguments 객체의 length 와 함수 객체의 length 값은 다를 수 있다. 둘은 각각 인자의 개수, 매개변수의 개수를 가리킨다.

3. name 프로퍼티

함수의 이름을 나타낸다.
ES5에서 익명 함수 표현식의 경우 name프로퍼티는 빈문자열을 갖고 ES6에서는 함수 객체를 가리키는 식별자를 값으로 가진다.

4. prototype 프로퍼티 **중요

생성자 함수로 호출할 수 있는 함수 객체, 즉 constructor 만이 소유하는 프로퍼티다.

  • 함수객체는 prototype 프로퍼티를 소유하지만
  • 일반객체는 prototype 프로퍼티를 소유하지 않는다.
  • 함수가 생성자 함수로 호출될 때 생성할 인스턴스의 프로토타입 객체를 가리킨다.
(function () {}).hasOwnProperty("prototype"); // true
({}).hasOwnProperty("prototype"); // false

고차함수?

고차 함수(higher order function)는 함수를 전달인자(argument)로 받을 수 있고, 함수를 리턴할 수 있는 함수이다.

콜백함수?

다른 함수(caller)의 전달인자(argument)로 전달되는 함수

--> 이 두 개념은 서로 상관관계가 있어서 같이 알아두자!

왜 고차함수를 사용할까?

수준 높은 추상화가 가능하기 때문이다.
추상화? 복잡한 어떤 것을 압축해서 핵심만 추출한 상태로 만드는 것 이라고 생각하면 편하다.

고차 함수 = 함수를 전달받거나 함수를 리턴한다 = 사고(함수)에 대한 복잡한 로직은 감추어져 있다 => 사고 수준에서의 추상화

일반적인 값의 추상화와 함수의 추상화보다 보다 높은 수준에서 생각할 수 있다.

  • 값 수준의 추상화: 단순히 값(value)을 전달받아 처리하는 수준
  • 사고의 추상화: 함수(사고의 묶음)를 전달받아 처리하는 수준

예시)

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

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

/*
 * 함수 doubleAdder는 고차 함수이다.
 * 함수 doubleAdder의 인자 func는 함수 doubleAdder의 콜백 함수다.
 * 함수 double은 함수 doubleAdder의 콜백으로 전달되었습니다. 
 즉, 함수 double은 고차 함수 doubleAdder의 콜백함수가 되는 것이다.
 */

// doubleAdder(5, double)는 함수이므로 함수 호출이 가능하다.
doubleAdder(5, double)(3); //  13

// doubleAdder가 리턴하는 함수를 변수에 저장할 수 있다. (일급 객체)
const addTwice3 = doubleAdder(3, double);
addTwice3(2); //  8

내장 고차 함수

js에 기본적으로 내장 되어있는 고차함수이며 배열 메소드들 중 일부가 고차함수에 해당한다.

  • 자주 쓰이는 메서드 : forEach, find, filter, map, reduce, sort, some, every

오늘은 이 중에서 map, filter, reduce 에 대해 알아보자.


먼저 3개의 내장 메서드 모두 Array의 내장 메서드이며 원본배열을 손상시키지 않는다.
또한 인자로 콜백함수를 받는다.


Array.prototype.map()

arr.map(callback(currentValue[, index[, array]])[, thisArg])

map() 메서드는 배열 내의 모든 요소 각각에 대하여 주어진 함수를 호출한 결과를 모아 새로운 배열을 반환한다.

Array.prototype.filter()

arr.filter(callback(element[, index[, array]])[, thisArg])

filter() 메서드는 주어진 함수의 테스트를 통과하는 모든 요소를 모아 새로운 배열로 반환한다.
각 요소를 시험할 함수(콜백함수)가 true를 반환하면 요소를 유지하고, false를 반환하면 버린다.

Array.prototype.reduce()

 arr.reduce(callback[, initialValue])

reduce() 메서드는 배열의 각 요소에 대해 주어진 리듀서 (reducer) 함수를 실행하고, 하나의 결과값을 반환한다.
리듀서 함수는 네 개의 인자를 가집니다.
1.누산기 (acc)
2.현재 값 (cur)
3.현재 인덱스 (idx)
4.원본 배열 (src)

reduce() 메서드는 초기값을 주고 안주고에 따라 콜백의 실행 횟수가 차이가 난다. 초기값을 준다면 주지 않은 경우보다 1번 더 콜백이 실행된다.

예)

[0, 1, 2, 3, 4].reduce(function(accumulator, currentValue, currentIndex, array) {
  return accumulator + currentValue;
});
callbackaccumulatorcurrentValuecurrentIndexarray반환 값
1번째 호출011[0, 1, 2, 3, 4]1
2번째 호출122[0, 1, 2, 3, 4]3
3번째 호출333[0, 1, 2, 3, 4]6
4번째 호출644[0, 1, 2, 3, 4]10

---> 반환 값은 10이 된다.

reduce()의 두 번째 인수로 초기값을 제공하는 경우

[0, 1, 2, 3, 4].reduce(function(accumulator, currentValue, currentIndex, array) {
  return accumulator + currentValue;
}, 10);
callbackaccumulatorcurrentValuecurrentIndexarray반환값
1번째 호출1000[0, 1, 2, 3, 4]10
2번째 호출1011[0, 1, 2, 3, 4]11
3번째 호출1122[0, 1, 2, 3, 4]13
4번째 호출1333[0, 1, 2, 3, 4]16
5번째 호출1644[0, 1, 2, 3, 4]20

추가적으로 알면 좋은 reduce() 사용법
flatMap()메서드와 reduce() + concat() 메서드로 2차원 배열을 평탄화 할 수 있다.

const arr = [
  [1, 2],
  [3, 4],
  [5, 6],
];
// reduce와 concat 이용
const joinReduveArr = arr.reduce(function (acc, val) {
  return acc.concat(val);
});
console.log(joinReduveArr);
//flatMap 이용
const joinFlatMapArr = arr.flatMap((x) => x);
console.log(joinFlatMapArr);

위 코드는 동일하게 [ 1, 2, 3, 4, 5, 6 ] 이 출력된다.

출처 및 참고 : https://developer.mozilla.org/ko/

profile
프론트엔드 개발자를 꿈꾸는 원호잇!

0개의 댓글