12 / 함수 Function

JinKris·2022년 2월 1일
0
post-thumbnail

함수는 일련의 과정을 문으로 구현하고 코드 블록으로 감싸서 하나의 실행 단위로 정의한 것이다. 내부로 전달받는 변수를 매개변수parameter, 입력을 인수argument, 출력을 반환값return value이라 한다.
함수는 함수 정의를 통해 생성하며 호출function call/invoke을 통해 실행된다.

자바스크립트 함수

자바스크립트의 함수는 객체 타입의 값이다.
일반 객체는 호출할 수 없지만 함수는 호출할 수 있다.
또 일반 객체에는 없는 함수 객체만의 고유한 프로퍼티를 갖는다.

함수 리터럴
함수는 객체이기에 객체 리터럴로 객체를 생성하는 것처럼
함수 리터럴로 생성할 수 있다.

// 이름은 생략할 수 있다.
let f = function add(x,y) {
	return x + y;
};

함수 이름(add)은 함수 몸체 내에서만 참조할 수 있는 식별자다.

함수 정의

함수 정의란 함수를 호출하기 이전에 인수를 전달받을 매개변수와 실행할 문들, 그리고 반환할 값을 지정하는 것을 말한다. (함수 선언문이 평가되면 식별자가 암묵적으로 생성되고 함수 객체가 할당된다. 이를 함수 정의라고 표현한다)
함수를 정의하는 방법에는 4가지가 있다.
함수 선언문, 함수 표현식, Fucntion 생성자 함수, 화살표 함수...

1) 함수 선언문

function add(x,y) {
	return x+y;
}

리터럴과 형태가 동일하다
단, 함수 리터럴은 이름을 생략할 수 있으나 함수 선언문은 함수 이름을 생략할 수 없다.

선언문은 표현식이 아닌 문이다. (선언문을 실행하면 완료 값 undefined가 출력된다 / 표현식인 문이라면 완료값 대신 표현식이 평가되어 생성된 함수가 출력되어야 한다 또 표현식인 문은 변수에 할당할 수 있다)

앞서 설명한 함수 리터럴과 함수 선언문은 이름을 생략할 수 있는 것을 빼고 형태가 매우 유사하다. 함수 리터럴을 피연산자로 사용하면 함수 선언문이 아니라 함수 리터럴 표현식으로 해석되는데, 함수 리터럴 표현식과 선언문 모두 함수가 생성되는 것은 동일하지만 내부 동작에 차이가 있다.

// 함수 선언문 (이름 생략 불가)
funtion foo() { console.log('foo'); }

// 함수 리터럴 표현식 (그룹 연산자() 내부에 있어서 표현식)
(function foo2() {console.log('foo2');})

위처럼 선언문으로 생성된 foo는 호출할 수 있으나 함수 리터럴 표현식으로 생성된 foo2는 호출할 수 없다.


함수 이름은 함수 몸체 내에서만 참조할 수 있는 식별자다.
이는 함수 몸체 외부에서는 함수 이름으로 함수를 참조할 수 없으므로 외부에서는 이름으로 호출할 수 없다는 의미다. 즉 함수를 가리키는 식별자가 없다는 것과 마찬가지다.
(함수 이름 foo2는 함수 몸체 내에서만 참조할 수 있는 식별자이므로 함수를 호출할 수 없다)


선언문으로 정의된 함수는 foo라는 이름으로 호출할 수 있다. foo는 함수 객체를 가리키는 식별자로 자바스크립트 엔진이 암묵적으로 생성한 식별자다.
자바스크립트 엔진은 함수 선언문을 해석해 함수 객체를 생성하는데 이때 함수 이름과는 별도로 생성된 함수 객체를 가리키는 식별자가 필요하다, 식별자가 없으면 생성된 함수 객체를 참조하거나 호출할 수 없기 때문이다. 따라서 자바스크립트 엔진은 생성된 함수를 호출하기 위해 함수 이름과 동일한 이름의 식별자를 암묵적으로 생성하고 거기에 함수 객체를 할당한다.
즉, 함수는 함수 이름으로 호출하는 것이 아니라 함수 객체를 가리키는 식별자로 호출함을 알 수 있다.

2) 함수 표현식

자바스크립트 함수는 일급 객체다. 일급 객체라는 것은 함수를 값처럼 변수에 할당할 수도 있고 프로퍼티 값이 될수도 있으며 배열의 요소가 될수도 있는등 자유롭게 사용할 수 있다는 의미다.
함수 리터럴의 함수 이름을 생략한것을 익명 함수라 한다.

함수 호이스팅 :
함수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는것을 의미한다.
선언문이 런타임 이전에 JS엔진에 의해 먼저 실행되어 식별자를 생성하고
생성된 식별자는 함수 객체로 초기화된다(var키워드 변수 호이스팅에서는 생성된 식별자는 undefined로 초기화된다)
함수 표현식으로 함수를 정의하면 변수 호이스팅이 발생한다.

호이스팅은 까다롭기 때문에 ...
선언문 대신 표현식을 사용하는 것을 권장하기도 ...

3) Function 생성자 함수

자바스크립트가 기본 제공하는 빌트인 함수인 Function 생성자 함수에 매개변수 목록과 함수 몸체를 문자열로 전달하면서 new 연산자와 함께 호출하면 함수 객체를 생성해서 반환한다.
바람직하지 않은 방법이다... (화살표 함수로 대체!)

4) 화살표 함수

ES6에서 도입된 방법으로, function 키워드 대신 =>를 사용한다. 화살표 함수는 항상 익명 함수로 정의한다.

const add = (x,y) => x + y;
console.log(add(2,5));

화살표 함수는 생성자 함수로 사용할 수 없으며, 기존 함수와 this 바인딩 방식이 다르고, prototype 프로퍼티가 없으며 arguments 객체를 생성하지 않는다. (26.3절 참고)

함수 호출

올바르지 않은 매개변수의 전달은 에러를 발생시킬 수 있다.
함수 호출은 표현식이다 (return 키워드와 표현식으로 이뤄진 반환문).
반환문은 함수 몸체 내부에서만 사용할 수 있다.
(Node.js에서는 파일별로 독립적인 스코프를 갖기에 파일의 가장 바깥 영역에 반환문을 사용해도 에러가 발생하지 않는다)

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

매개변수는 함수 몸체 내부에서 변수와 동일하게 취급되므로 타입에 따라 값에 의한 전달(원시값), 참조에 의한 전달(객체) 방식을 따른다.

function changeVal(primitive,obj){
	primitive += 100;
    obj.name = 'kim';
}

var num = 100;
var person = { name: 'Lee' };
changeVal(num,person);

// 원시 값은 원본이 훼손되지 않는다.
console.log(num); // 100
// 객체는 원본이 훼손된다.
console.log(person); // {name : "kim"}

객체가 훼손되는 문제를 해결하는 방법 중 하나는 불변 객체(16.5절)로 만들어 사용하는 것이다.

다양한 함수의 형태

1) 즉시 실행 함수
정의와 동시에 즉시 호출되는 함수를 말한다.

(function () {
	//...
}());

(function () {
	//...
})();

2) 재귀 함수
재귀 호출을 멈출 수 있는 탈출 조건을 반드시 만들어야 함에 유의

3) 중첩 함수/내부 함수
함수 내부에 정의된 함수를 중첩 함수 또는 내부 함수라 한다. 그리고 중첨 함수를 포함하는 함수는 외부 함수라 부른다. 일반적으로 중첩 함수는 외부 함수를 돕는 헬퍼 함수의 역할을 한다. (중첩 함수는 외부 함수의 변수를 참조할 수 있다)

4) 콜백 함수
함수의 매개변수를 통해 다른 함수의 내부로 전달되는 함수를 콜백 함수라고 하며, 매개 변수를 통해 함수의 외부에서 콜백 함수를 전달받은 함수를 고차 함수라고 한다.
다시말해.. 콜백 함수는 고차 함수에 의해 호출되며 고차 함수는 필요에 따라 콜백 함수에 인수를 전달할 수 있다. 따라서 고차 함수에 콜백 함수를 전달할 때 콜백 함수를 호출하지 않고 함수 자체를 전달해야 한다.

function repeat(n,func) {
	for(let i=0;i < n; i++){
    	for(i);
    }
}
var logAll = function (i) {
	console.log(i);
};
var logOdds = function (i) {
	if(i%2) console.log(i);
};
// logAll함수를 콜백함수로 고차함수 repeat에 전달
repeat(5, logAll); // 0 1 2 3 4 
repeat(5, logOdds); // 1 3

// 배열 고차 함수 reduce
let res = [1,2,3].reduce(function(acc,cur){
	return acc+cur;
},0);
console.log(res); // 6

5) 순수 함수와 비순수 함수
함수형 프로그래밍에서
어떤 외부 상태에 의존하지도 않고 변경하지도 않는, 즉 부수 효과가 없는 함수를 순수 함수라 하고, 외부 상태에 의존하거나 외부 상태를 변경하는, 즉 부수 효과가 있는 함수를 비순수 함수라고 한다.

var count = 0;

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

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

함수형 프로그래밍은 순수함수와 보조함수의 조합을 통해 프로그램의 안정성을 높이려는 방식을 추구한다.

profile
hello world

0개의 댓글