모던 자바스크립트 Deep Dive : 12장 함수

EdLee·2022년 10월 29일

javascript

목록 보기
2/37

12장 함수

1. 함수의 정의 방식


함수 정의 방식예시
함수 선언문
(일반 함수)
function add(x,y) {
return x+y;
}
함수 표현식
(익명 함수)
var add = function (x,y) {
return x+y;
};
Function 생성자 함수var add = new function('x','y', 'return x+y;');
화살표 함수var add = (x,y)=> x+y;

1.1 함수 선언문과 함수 표현식의 차이

  • 함수 선언문을 함수 표현식처럼 쓰더라도 대게 자바스크립트 엔진은 오류를 내지 않고 해석을 해준다.
  • 반면 함수 표현식처럼 함수 이름을 생략하고 함수 선언문처럼 쓸 수는 없다.
  • 함수 선언문에 이름이 없다면 호출할 방법이 있을까?
// SyntaxError: Function statements require a function name
function (x,y) {
  return x + y;
}

// 함수 선언문
function add1(x,y) {
  return x + y;
} // 코드블록이므로 ";"는 붙이지 않는다
console.log(add1(1, 2)); // 3

// 함수 표현식
var add2 = function(x,y) {
  return x + y;
}; // 리터럴이므로 ";" 를 붙여주는게 맞다
console.log(add2(1, 2)); // 3

// 함수 선언문? 표현식?
var add3 = function add4(x,y) {
  return x + y;
} // ";" 없다고 오류가 나지는 않는다

console.log(add3(1, 2)); // 3
console.log(add4(1, 2)); // ReferenceError: add4 is not defined, add4 선언이 무시됐다

1.2 함수 생성 시점과 함수 호이스팅

함수 호이스팅이란?

함수 선언문으로 정의한 함수는 선언한 위치보다 위에서 호출할 수 있다

  • 모든 선언문은 런타임 이전에 JS엔진에 의해 먼저 실행된다.
  • 마찬가지로 함수 선언문도 JS엔진이 미리 객체를 생성해 놓는다.
  • 반면 함수 표현식은 변수 할당문이므로, 변수에 할당되는 시점인 런타임에 평가되어 객체가 생성된다.

예시

// 함수 호출
console.dir(add); // f add(x,y)
console.dir(sub); // sub 변수는 변수 호이스팅에 의해 생성이 된 상태

// 함수 호출
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;
}

1.3 Function 생성자 함수

  • 사용하지 않는 것을 권장
  • function 생성자 함수는 클로저를 생성하지 않는다.
  • 클로저는 24장 참고
var add = new Function('x','y', 'return x + y;');
console.log(add(1,2)); // 3

// 책의 예시 코드는 오류가 있다
var add2 = (function () {
  var a = 10;
  return new Function('x','y', 'return x + y + ' + a + ';'); // 문자열에 a를 삽입한다는 것에 유의
}());
console.log(add2(1,2)); // 13

1.4 화살표 함수

  • 항상 익명 함수로 정의한다
  • 기존 함수 선언문, 함수 표현식을 대체하기 위한 것이 아니며, 동작과 용도가 다르다

화살표 함수의 특징

1) 생성자 함수로 사용할 수 없다
2) this 바인딩 방식이 다르다
3) prototype 프로퍼티가 없다
4) arguments 객체를 생성하지 않는다

  • 자세한 건 26장 참고

2. 함수 호출


2.1 매개변수

  • 매개변수 개수에 제한은 없다
  • 매개변수 기본값 사용 가능
  • 매개변수의 타입이 정해져 있지 않다는 것에 유의
function add(a = 4,b = 5,c = 6) {
  return a + b + c;
}

console.log(add(3,2,1)); // 6
console.log(add(3,2)); // 11
console.log(add(3)); // 14
console.log(add()); // 15
console.log(add(3, c = 1)); // 10, 이런 문법은 지원하지 않고, 인자 순서만 본다
console.log(add('1','2','3')); // '123', 인자에 타입이 정해져 있지 않다

3. 원시값 매개변수와 객체 매개변수의 비교


  • 원시값은 값에 의한 전달
  • 객체는 참조에 의한 전달
  • 매개변수에서도 동일하게 동작
function changeVal(primitive, obj) {
    primitive += 100;
    obj.name = 'Kim';
}

var primVal = 100;
var objVal = { name : 'Lee' };

console.log(primVal); // 100
console.log(objVal.name); // Lee

changeVal(primVal, objVal);

// 원시 값은 불변
console.log(primVal); // 100
//객체는 mutable
console.log(objVal.name); // Kim

4. 함수의 종류


4.1 즉시 실행 함수

  • 함수가 정의된 위치에서 즉시 호출되는 함수
  • 단 한 번만 호출됨
  • 익명 함수를 사용하는 것이 일반적
  • 기명 함수를 사용해도 함수 호이스팅이 일어나거나, 다시 호출할 수 없음
console.log('start!');

var addVal = (function add(a, b) { // 기명함수로 정의는 가능
  console.log('function!'); // 함수 호이스팅이 일어나지는 않음
  return a + b;
} (1,2));

console.log(addVal);
console.log(add); // add is not defined, 재호출 불가능

/**
start!
function!
3
Error : add is not defined
*/

4.2 중첩 함수

  • 함수 내부 또는 코드 블록에 정의된 함수
  • 중첩 함수(nested function), 또는 내부 함수(inner function)라고 한다.
  • 중첩 함수를 가진 함수는 외부 함수(outer function)
function outer() {
  var x = 1;

  function inner() {
    var y = 2;
    console.log(x + y); // 바깥 스코프의 변수 x 참조 가능
  }

  inner();
}

outer(); // 3
inner(); // inner is not defined

주의 사항

  • 중첩 함수는 함수 호이스팅이 일어나지 않는다
  • 스코프와 클로저와 깊은 연관이 있으므로, 해당 챕터 참고
console.log(add(1,2)); // add is not a function

var a = true;
if(a) {
  function add(x,y) {
     return x + y; 
  }
}

4.3 콜백 함수

  • 다른 함수에 인자로써 전달되는 함수
  • 콜백 함수를 매개변수로 갖는 함수는 고차 함수(Higher-Order Function)
function repeat(n, callback) {
  for (var i = 0; i < n; i++) {
    callback(i);
  }
}

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

// 함수 참조를 전달한다. callback()를 전달하면 안된다.
repeat(5, callback); // 0 1 2 3 4

// 익명 함수 리터럴도 전달 가능하다
repeat(5, function (i) {
  if (i % 2) console.log(i);
}); // 1 3

4.4 순수 함수와 비순수 함수

순수 함수(pure function)

순수 함수 : 부수효과가 없는 함수

  • 외부 상태에 의존하지 않는다
  • 외부 상태를 변경하지 않는다
    ※ 외부 상태란? 전역 변수, 서버 데이터, 파일, Console, DOM 등

순수 함수는,
1. 하나 이상의 인자를 갖는다.
2. 동일한 인자가 전달되면 언제나 동일한 값을 반환하는 것을 보장한다
3. 인자를 변경하지 않는다
4. 외부 상태를 변경하지 않는다

var count = 0;

function increase(n) {
  return ++n;
}

increase(count);
console.log(count); // 0, count 는 그대로

count = increase(count); // 변수에 재할당
console.log(count); // 1

비순수 함수(impure function)

  • 외부 상태에 의존하거나,
  • 외부 상태를 변경한다

    비순수 함수 : 부수효과가 있는 함수

var count = 0;

function increase() {
  return ++count;
}

increase();
console.log(count); // 1, count가 변경됐다
console.log(increase()); // 2, 인자도 없는데 return이 달라졌다

결론?

  • 비순수 함수는 코드의 복잡성을 증가시키고, 가독성을 해치는 등 오류 발생의 원인이 될 수 있다.
  • 따라서 비순수 함수는 지양하고 되도록 순수 함수를 사용해야 한다

    외부 값은 인자를 통해서 받고, 스코프는 가능한 사용하지 말 것
    인자는 불변인 것이 좋다

의문점

  • 책에는 객체를 전달받으면 비순수 함수라고 적혀있다
  • 그런데...js는 함수 인자의 타입을 정하질 않는데, 어떻게 비순수함수 여부를 알 수 있는 것인지??😐
  • 내부에서 객체의 변경만 없다면 순수함수로 봐도 되지 않을까?

0개의 댓글