자바스크립트의 함수는 C, C++과 같은 언어와 다른 매우 독특한 문법이다.
자바스크립트 함수의 특징을 알아보자
console.log(add(2, 7)); // 9
function add(x, y){
return x + y;
}
자바스크립트는 인터프리터언어라서 위쪽부터 차례대로 한 줄 씩 실행되는데 어떻게 함수 사용 명령을 먼저 사용할 수 있지?
fucntion으로 정의된 함수를 문서 위쪽으로 배치시키는 호이스팅이라는 기능이 있다. (호이스팅은 추후 더 자세히 다뤄보자, 일단 자바스크립트에서 함수를 선언하면 문서의 맨 위로 끌어 올려진다는 것으로 기억해두자)
긴말 필요 없이 바로 예시로 보자
function add(x, y){
return x + y;
}
function키워드, 함수의 이름을 결합한 다른 언어의 함수와 비슷한 형태를 갖는 선언방법이 있다. (얘는 호이스팅 됨, 기억!).....❓어떻게 이런 일이
자바스크립트에서 함수는 값, 즉 객체로 취급된다. 객체는 변수에 할당할 수 있었다. 그렇다면?
const add = add(x, y){
return x + y;
}
console.log(add(7,3)) // 10
상수의 이름을 함수의 이름으로 정해주었기 때문에 일반적인 선언처럼 function다음에 함수 이름을 붙일 필요가 없다.
(변수에도 대입이 가능하고 얼마든지 변경할 수 있다.)
함수를 호출하는 방법은 일반적인 선언의 함수와 동일하다.
const add = (x, y) => x + y;
console.log(add(7,3)) //10
인자를 받고 값을 반환하는 용도로 특히 많이 사용한다.
화살표 함수는 function키워드 때로는 블록{}으로 묶어 줄 필요가 없다.
function add(x, y){
return x + y;
}
이런식으로 함수의 형태가 간단한 경우(인자로 반환값을 바로 만들어내어 반환하는 경우)에 사용할 수 있다.
만약 조금 더 복잡한 함수라면 블록{}을 사용해 함수의 동작을 구현할 수 있다.
const add = (x, y) => {
console.log(`${x} + ${y} = ?`);
return x + y;
}
console.log(add(7,3));
// 7 + 3 = ?
// 10
function으로 선언된 함수와 대입된 함수, 화살표 함수와 차이점이 존재한다.console.log(add(7,3)) // 10
const add = add(x, y){
return x + y;
}
그래서 해당 코드는 오류가 발생한다.
function add(x, y) { return x + y; }
console.log(typeof add); // function
console.log(add); // f add (x, y) { return x + y; }
console.log(add instanceof Object); // true
출력된 결과의 내용을 미루어 볼때 자바스크립트의 함수는 function이라는 객체라는 사실을 알 수 있다.
function isOddNum (number) {
console.log(
(number % 2 ? '홀' : '짝')
+ '수입니다.'
);
return number % 2 ? true : false;
};
const checkIfOdd = isOddNum; // 뒤에 괄호 없음 유의
console.log(checkIfOdd(23));
// 홀수입니다.
// true
function으로 함수를 선언하고 괄호를 붙이지 않은채 상수에 할당하고 있다.
할당된 변수나, 상수의 이름으로 할당한 함수를 호출 할 수 있다.
물론 함수의 이름으로도 호출 할 수 있다.
상수나 변수는 할당된 함수를 참조하기때문에 실행 할 수 있다.
함수도 객체니까!
💡함수는 객체와 배열의 값으로도 할당이 가능하다.
let person = {
name: '홍길동',
age: 30,
married: true,
introduce: function (formal) {
return formal
? '안녕하십니까. 홍길동 대리라고 합니다.'
: '안녕하세요, 홍길동이라고 해요.';
}
};
console.log(person.introduce(true)); // 안녕하십니까. 홍길동 대리라고 합니다.
console.log(person.introduce(false)); // 안녕하세요, 홍길동이라고 해요.
let arithmetics = [
(a, b) => a + b,
(a, b) => a - b,
(a, b) => a * b,
(a, b) => a / b
];
for (arm of arithmetics) {
console.log(arm(5, 3));
}
/*
8
2
15
1.6666666666666667
*/
⭐ 객체에 함수 프로퍼티를 포함할 때 기억해야 할 것
let person = {
name: '홍길동',
age: 30,
married: true,
introduce: function () {
return `저는 ${this.name}, ${this.age}살이고 `
+ `${this.married ? '기혼' : '미혼'}입니다.`;
}
}
console.log(person.introduce()); // 저는 홍길동, 30살이고 기혼입니다.
person이라는 객체에 introduce라는 함수 프로퍼티가 존재한다. 해당 함수가 객체의 다른 프로퍼티에 접근하려면 this, 즉 해당 객체의 프로퍼티를 가져와야 한다.
함수의 형태가 간단하니 화살표 함수로 바꿔 볼 수 있겠다.
let person = {
name: '홍길동',
age: 30,
married: true,
introduce: () => {
return `저는 ${this.name}, ${this.age}살이고 `
+ `${this.married ? '기혼' : '미혼'}입니다.`;
}
}
console.log(person.introduce()); // 저는 , undefined살이고 미혼입니다.
?! 출력 결과가 이상하다. name과 age에 접근이 되지 않았다. introduce 프로퍼티 함수에 this를 콘솔에 출력해보자
Window {0: Window, 1: global, window: Window, self: Window,
document: document, name: '', location: Location, …}
.... 왜 전역 객체인 window를 출력할까? this에 대해서 자세히 다루는 포스트를 만들어야 겠다.
객체 리터럴의 프로퍼티로
this를 사용하는 화살표 함수를 사용하지 말자.
let list = [1, 2, 3, 4, 5];
// 배열의 요소들을 인자로 어떤 함수를 실행하는 함수
function doInArray (array, func) {
for (item of array) {
func(item);
}
}
// console.log - console이란 객체에서 log란 키에 할당된 함수
doInArray(list, console.log);
/*
1
2
3
4
5
*/
해당 코드에서는 doInArray가 고차함수, console.log가 콜백함수가 되겠다.
function doNTimes (func, repeat, x, y) {
let result = x;
for (i = 0; i < repeat; i++) {
result = func(result, y);
}
return result;
}
console.log(
doNTimes((x, y) => x * y, 3, 5, 2),
doNTimes((x, y) => x / y, 3, 5, 2),
);
// 40 0.625
콜백함수는 이후 함수형 프로그래밍에서 아주 유용하게 사용된다
function getIntroFunc (name, formal) {
return formal
? function () {
console.log(`안녕하십니까, ${name}입니다.`);
} : function () {
console.log(`안녕하세요~ ${name}이라고 해요.`);
}
}
const hongIntro = getIntroFunc('홍길동', true);
const jeonIntro = getIntroFunc('전우치', false);
hongIntro();
jeonIntro();
반환 값인 함수에는 이름을 붙일 필요는 없다.
반환 된 함수는 상수나, 변수에 저장 되어 사용할 수 있다.
함수를 반환 할 수 있는 기능은 필요에 따라서 함수, 즉 기능을 생성해 낼 수 있다는 의미이다.
⭐ 불변성
다음 코드를 실행해 보자
let x = 1;
let y = {
name: '홍길동',
age: 15
}
let z = [1, 2, 3];
function changeValue (a, b, c) {
a++;
b.name = '전우치';
b.age++;
c[0]++;
console.log(a, b, c); // 2 {name: '전우치', age: 16} [2, 2, 3]
}
changeValue(x, y, z);
음! 성공적으로 x, y, z 값이 바뀌었군 출력해 볼까?
console.log(x, y, z); // 1 {name: '전우치', age: 16} [2, 2, 3]
🙄❓❓❓❓ 왜 x값이 그대로지
함수에 원시값을 넣어서 사용 할 때는 그 복사본을 사용한다. 그래서 원시 타입은 인자로 들어간 함수 내에서의 변경에 영향을 받지 않는다.
반면에 참조 타입(객체, 배열 등)은 인자로 들어간 함수 내에서 요소가 변하면 실제의 값도 변한다. 함수에 복사된 값은 참조값이라 객체나 배열을 가리키기 때문이다.
그런데 저런식으로 함수의 주어진 인자를 변경하는 것은 좋지 않다. 꼭 필요할 때만 변경하도록 하자.
기본적으로 함수는 외부에 영향을 받지 않고 자신의 매개변수만을 제어하는 것이 이상적이다.
자바스크립트에서의 함수는 일급 객체로 취급되며 할당, 반환, 매개변수로 사용할 수 있다. 함수를 변수에 할당해 참조하게 하여 변수의 이름으로 호출할 수 있다. 또한, 함수속에서 함수를 반환 할 수 있다. 마지막으로 함수의 매개변수로 전달해 콜백함수로 사용할 수 있다. 함수도 객체이기 때문에 여러가지의 프로퍼티를 가지고 있는데 그 중에서 prototype이라는 프로퍼티는 오직 함수에만 존재하며 생성자 함수로서 사용될 때 생성될 인스턴스의 프로토타입으로 사용된다.