12장. 함수

Happhee·2022년 1월 21일
0

JS : Depp Dive

목록 보기
9/35
post-thumbnail

1. 함수란?

입력값을 받아 출력값을 내보내는 일련의 과정
일련의 과정을 으로 구현하고 코드 블록으로 감싸 하나의 실행 단위로 정의

2. 함수를 사용하는 이유

  • 코드의 재사용성
  • 편의성
  • 코드의 신뢰성
  • 코드의 가독성

3. 함수 리터럴

함수는 객체 타입의 값이기에, 함수 리터럴로 생성 가능
함수 리터럴 -> function 함수이름 매개변수목록 함수 몸체로 구성

값으로 할당

//변수에 함수 리터럴을 할당 
var f = function add(x,y) {
  return x+y;
}

일반 객체는 호출할 수 없지만, 함수는 호출할 수 있다

4. 함수 정의

  • 함수 선언문
function add ( ) { }	```

- 익명 함수 표현식
```js
var add = function () { }```

- 기명 함수 표현식
```js
var add2 = function add( ){ }```

변수는 선언한다고 하지만, 함수는 ```정의```한다고 말한다

# 5. 함수 선언문
> 함수 이름을 생략할 수 없으며
표현식이 아닌 문이다
만약, 표현식인 문이라면 undefined가 아닌 평가된 값이 콘솔에 나와야하지만, 그렇지 않다


```js
// 함수 선언문은 함수 이름을 생략할 수 없다.
function (x, y) {
  return x + y;
}
// SyntaxError: Function statements require a function name

// 함수 선언문은 표현식이 아닌 문이므로 변수에 할당할 수 없다.
// 하지만 함수 선언문이 변수에 할당되는 것처럼 보인다.
var add = function add(x, y) {
  return x + y;
};

// 함수 호출
console.log(add(2, 5)); // 7

자바스크립트 엔진은 생성된 함수를 호출하기 위해 함수이름과 동일한 이름의 식별자를 생성한 뒤 거기에 함수 객체를 할당한다

6. 함수 생성 시점과 함수 호이스팅

함수 선언문으로 정의한 함수와 함수 표현식으로 정의한 함수의 생성 시점은 다르다
함수 선언문은 코드의 선두로 끌어올려진 것 처럼 동작하는 함수 호이스팅의 특징을 갖고 있지만,
함수 표현식은 함수 호이스팅이 아닌 변수 호이스팅이 발생한다
즉, 변수 할당문의 값은 할당문이 실행되는 시점인 런타임에 평가되기 때문에, 함수 표현식의 함수 리터럴도 할당문이 실행되는 시점에 평가되어 함수 객체가 된다.

아래 예제를 보자

//add 
//sub

// 함수 참조
console.dir(add); // ƒ add(x, y)
console.dir(sub); // undefined	-> 값이 할당되기 전

// 함수 호출
console.log(add(2, 5)); // 7
console.log(sub(2, 5)); // TypeError: sub is not a function

// 함수 선언문
function add(x, y) {
  return x + y;
}

// 함수 표현식
var sub = function (x, y) {
  return x - y;
};
  • Function 생성자 함수
//같은 의미
var add1 = function(x,y){ return x+y; }
var add2 = new Function('x', 'y', 'return x+y');

var add1 = (function () {
  var a = 10;
  return function (x, y) {
    return x + y + a;
  };
}());

console.log(add1(1, 2)); // 13

var add2 = (function () {
  var a = 10;
  return new Function('x', 'y', 'return x + y + a;');
}());


console.log(add2(1, 2)); // ReferenceError: a is not defined

클로저를 생성하지 않아 (=외부변수를 참조하지 못한다) 바람직하진 않다

  • 화살표함수
const add = (x,y) => {
	return x+y;
}
console.log(add(2,4)) 	//6

this바인딩 방식이 다르고, 생성자 함수로 사용할 수 없으며, prototype 프로퍼티도 없고, arguments 객체도 생성하지 않는다.

7. 함수 호출

함수를 실행하기 위해 필요한 값을 함수 내부로 전달할 필요가 있으면,
매개변수를 통해 인수를 전달한다.

  • 매개변수의 스코프는 함수 내부이다
  • 초과된 인수는 arguments 객체에 보관된다

특징

  • 자바스크립트 함수는 매개변수와 인수의 개수가 일치하는지는 확인하지 않는다
  • 자바스크립트는 동적 타입언어이기에 , 매개변수 타입을 사전에 지정할 수 없다
  • ES6 : default 값 지정 가능
function add(a = 0, b = 0, c = 0) {
  return a + b + c;
}
console.log(add(1, 2, 3)); // 6
console.log(add(1, 2)); // 3
console.log(add(1)); // 1
console.log(add()); // 0
  • 반환문은 return 키워드 뒤에 오는 표현식을 평가해 반환하며 생략 가능하다

8. 참조에 의한 전달과 외부 상태의 변경

원시 값은 값에 의한 전달, 객체는 참조에 의한 전달 방식으로 동작하는데
매개변수도 함수 내부에서 변수와 동일하게 취급되므로 매개변수 타입에 따라
값에 의한 전달, 참조에 의한 전달 방식을 그대로 따른다

// 매개변수 primitive는 원시값을 전달받고, 매개변수 obj는 객체를 전달받는다.
function changeVal(primitive, obj) {
  primitive += 100;
  obj.name = 'Kim';
}

// 외부 상태
var num = 100;
var person = { name: 'Lee' };

console.log(num); // 100
console.log(person); // {name: "Lee"}

// 원시값은 값 자체가 복사되어 전달되고 객체는 참조값이 복사되어 전달된다.
changeVal(num, person);

// 원시값은 원본이 훼손되지 않는다.
console.log(num); // 100

// 객체는 원본이 훼손된다. 
// 순수함수가 아니다
console.log(person); // {name: "Kim"}
  • 순수함수
    외부 상태를 변경하지 않는 함수

9. 다양한 함수의 형태

  • 즉시 실행 함수
    그룹 연산자로 감싸 주어야 한다
    익명 즉시 실행 함수 또는 기명 즉시 실행 함수로 작성하지만, 기명함수라고 해서 여러번 호출할 수 있는 것이 아니다!!
// 익명 즉시 실행 함수
(function () {
  var a = 3;
  var b = 5;
  return a * b;
}());

// 기명 즉시 실행 함수
(function foo() {
  var a = 3;
  var b = 5;
  return a * b;
}());

foo(); // ReferenceError: foo is not defined

// 즉시 실행 함수도 일반 함수처럼 값을 반환할 수 있다.
var res = (function () {
  var a = 3;
  var b = 5;
  return a * b;
}());

console.log(res); // 15

// 즉시 실행 함수에도 일반 함수처럼 인수를 전달할 수 있다.
res = (function (a, b) {
  return a * b;
}(3, 5));

console.log(res); // 15
  • 재귀 함수
function countdown(n) {
  if (n < 0) return;
  console.log(n);
  countdown(n - 1); // 재귀 호출
}
countdown(10);

function factorial(n) {
  if (n <= 1) return 1;

  var res = n;
  while (--n) res *= n;
  return res;
}

console.log(factorial(0)); // 0! = 1
console.log(factorial(1)); // 1! = 1
console.log(factorial(2)); // 2! = 2 * 1 = 2
console.log(factorial(3)); // 3! = 3 * 2 * 1 = 6
console.log(factorial(4)); // 4! = 4 * 3 * 1 * 1 = 24
console.log(factorial(5)); // 5! = 5 * 4 * 3 * 2 * 1 = 120
  • 중첩 함수
    함수 내부에 정의된 함수를 말함
    중첩함수는 외부함수내부에서만 호출할 수 있다
function outer() {
  var x = 1;

  // 중첩 함수
  function inner() {
    var y = 2;
    // 스코프 체인에 의해 외부 함수의 변수를 참조할 수 있다.
    console.log(x + y); // 3
  }

  inner();
}

outer();
  • 콜백 함수
    함수의 매개변수를 통해 다른 함수의 내부로 이를 전달되는 함수를 말함
    매개변수를 통해 함수의 외부에서 콜백 함수를 전달받은 함수를 고차 함수라고 하며
    고차함수는 콜백함수를 자신의 일부로 합성한다
// 외부에서 전달받은 f를 n만큼 반복 호출한다
function repeat(n, f) {
  for (var i = 0; i < n; i++) {
    f(i); // i를 전달하면서 f를 호출
  }
}

var logAll = function (i) {
  console.log(i);
};

// 반복 호출할 함수를 인수로 전달한다.
repeat(5, logAll); // 0 1 2 3 4

var logOdds = function (i) {
  if (i % 2) console.log(i);
};

// 반복 호출할 함수를 인수로 전달한다. 
//logOdds는 repeat라는 함수에 인자로 넘겨주는 콜백함수
repeat(5, logOdds); // 1 3

따라서, 콜백함수는 고차 함수에 의해 호출되고, 고차 함수는 필요에 따라 콜백 함수에 인수를 전달할 수 있다
비동기 처리에 활용되는 중요한 패턴이다

// 콜백 함수를 사용하는 고차 함수 map
var res = [1, 2, 3].map(function (item) {
  return item * 2;
});

console.log(res); // [2, 4, 6]

// 콜백 함수를 사용하는 고차 함수 filter
res = [1, 2, 3].filter(function (item) {
  return item % 2;
});

console.log(res); // [1, 3]

// 콜백 함수를 사용하는 고차 함수 reduce
res = [1, 2, 3].reduce(function (acc, cur) {
  return acc + cur;
}, 0);

console.log(res); // 6
  • 순수 함수와 비순수 함수
    순수함수는 외부 상태에 의존하지 않아, 한 값에 대한 결과가 하나로 고정된다
var count = 0; // 현재 카운트를 나타내는 상태

// 순수 함수 increase는 동일한 인수가 전달되면 언제나 동일한 값을 반환한다.
function increase(n) {
  return ++n;
}

// 순수 함수가 반환한 결과값을 변수에 재할당해서 상태를 변경
count = increase(count);
console.log(count); // 1

count = increase(count);
console.log(count); // 2

var count = 0; // 현재 카운트를 나타내는 상태: increase 함수에 의해 변화한다.

// 비순수 함수
function increase() {
  return ++count; // 외부 상태에 의존하며 외부 상태를 변경한다.
}

// 비순수 함수는 외부 상태(count)를 변경하므로 상태 변화를 추적하기 어려워진다.
increase();
console.log(count); // 1

increase();
console.log(count); // 2
profile
즐기면서 정확하게 나아가는 웹프론트엔드 개발자 https://happhee-dev.tistory.com/ 로 이전하였습니다

0개의 댓글