함수(function)
- 특정 문(statement)을 하나의 단위로 실행하는 집합.
- 파라미터(매개변수; input)를 처리하여 결과(output)를 만듬.
- 함수는 자신이 존재하는 컨텍스트(환경)에 따라 다양한 모습을 보임.
- 일면은 코드를 재사용하는 수단.
- 모든 함수는 바디
{}
가 있고, 바디는 함수를 구성하는 문의 모음.
- JS에서는 함수도 객체.
함수 정의 방법
함수 선언문(Function Declaration)
function hello(name) {
return 'Hello, ' + name + '!';
}
- 호이스팅에 의해 함수가 스코프 맨 위로 끌어올려지무로 어디서든 호출 가능.
- 코드의 가독성이 높아짐.
- 함수를 선언한 스코프 내에서만 호출 가능.
함수 표현식(Function Expression; 익명함수)
- 식별자가 없는 선언.
- 함수 표현식은 함수가 익명이 될 수도 있음을 의미.
- 함수 표현식으로 익명함수를 만들고 그 함수를 바로 변수 등에 할당 하기 위해.
const f = function () {
};
- 함수나 메서드의 매개변수로 넘길 수도 있고, 객체의 메서드 등 다양한 스코프에서 활용 가능.
- 호이스팅에 영향을 받지 않음.(식별자만 호이스팅.)
greet();
const greet = function(name) {
return `Hello, ${name}!`;
};
const g = function f(stop) {
if (stop) console.log(`f stopped`);
f(true);
};
g(false);
화살표 함수(화살표 표기법)
function
키워드 생략.
- 간결하게 표현 가능.
- 항상 익명 함수. (변수 할당은 가능, 이름 붙은 함수는 불가)
const hello = (name) => {
return `Hello, ${name}!`;
};
const result = hello('world');
console.log(result);
const hello = name => `Hello, ${name}!`;
const result = hello('world');
console.log(result);
this
가 정적으로 묶임.(전역 변수로만 작동함)
const obj1 = {
name: "Alice",
sayHello: () => {
console.log(`Hello, ${this.name}!`);
},
};
const obj2 = {
name: "Bob",
sayHello: obj1.sayHello,
};
obj1.sayHello();
obj2.sayHello();
- 객체 생성자로 사용 불가.
- 확산 연산자 사용 불가.
함수 호출(call, run, execute, invoke)
- 함수의 식별자(이름) 다음에
()
(파라미터; 매개변수) 작성하면 함수의 바디 실행.
- JS는 어떠한 표현식(주로 식별자표현식) 뒤에 괄호가 있으면, 함수라고 간주하고 호출.
- 함수가 아닌 값 뒤에 괄호를 붙이면 에러.
console.log()
또한 함수이며 매개변수 자리에 값(표현식 등)을 넣었음.
function hello(name) {
return `Hello, ${name}!`;
}
console.log(hello('world'));
- 함수 호출은 표현식 이고 즉, 값이 됨.
- 함수 호출의 값은 반환 값.
- 반환값:
return
(예외문) 키워드를 이용하여 함수를 즉시 종료하고 값을 반환. (반환 값)
함수 참조
- 함수의 식별자 다음에
()
를 작성하지 않으면 참조하는 것이며, 그 함수는 실행되지 않음.
function getGreeting() {
return 'Hello world!';
}
console.log(getGreeting);
- 함수를 참조하기만 할 수 있음은 JS를 매우 유연한 연어로 만듬.
- 함수를 다른 변수(또는 객체 프로퍼티, 배열 요소)에 할당하고 다른 이름으로 함수 호출 가능.
function getGreeting() {
return 'Hello world!';
}
const f = getGreeting;
f();
console.log(f());
function getGreeting() {
return 'Hello world!';
}
const o = {};
o.f = getGreeting;
console.log(o.f());
function getGreeting() {
return 'Hello world!';
}
const arr = [1, 2, 3];
arr[1] = getGreeting;
console.log(arr);
console.log(arr[1]());
매개변수(parameter, argument)
- 매개변수는 함수에 정보를 전달하기 위함.
- 함수가 호출 되기 전에는 존재하지 않음.
- 또한 매개변수는 함수 바디 안에서만 존재.
- 함수 안에서 변수에 값을 할당해도 블록문 밖의 변수에는 아무 영향이 없음.
function f(x) {
console.log(`f 내부: x=${x}`);
x = 5;
console.log(`f 내부: x=${x} (할당 후)`);
}
let x = 3;
console.log(`f를 호출하기 전: x=${x}`);
f(x);
console.log(`f를 호출한 다음: x=${x}`);
- 함수 안에서 객체를 변경(수정)하면, 바뀐 점이 반영.
- 원시 값과 객체의 핵심적인 차이점.
- 원시 값은 불변이기에 수정이 불가. (원시 값 자체가 불변, 다른 값 할당을 의미하지 않음.)
- 반면 객체는 변경(수정) 할 수 있음.
function f(o) {
o.message = '함수에서 객체를 수정';
o = {
message: '함수에서 만든 객체!',
};
console.log(`함수 내부의 o.message값: ${o.message}`);
}
let o = {
message: '초기값',
};
console.log(`f를 호출하기 전 o.message값: ${o.message}`);
f(o);
console.log(`f를 호출한 뒤 o.message값: ${o.message}`);
매개변수의 개수
- 어떤 함수를 호출하든 정해진 매개변수 숫자와 관계없이 매개변수를 전달 가능.
- 정해진 매개변수의 값보다 적게 제공하면 암시적으로
undefined
가 할당됨.
function f(x) {
return `f에서의 x값은: ${x}`;
}
console.log(f());
매개변수 해체
- 객체를 매개변수로 해체 가능.
- 프로퍼티가 없는 변수는
undefined
할당.
function getSentence({ subject, verb, object }) {
return `${subject} ${verb} ${object}`;
}
const o = {
subject: 'I',
verb: 'love',
object: 'javascript',
};
console.log(getSentence(o));
매개변수 기본값
function f(a, b) {
const apple = a || 1;
const banana = b || 3;
return `a + b = ${apple + banana}`;
}
console.log(f());
console.log(f(8));
console.log(f(,8));
function f(a = 1, b = 3) {
return `a + b = ${a + b}`;
}
console.log(f());
console.log(f(8));
console.log(f(,8));
const f = (a = 1, b = 3) => `a + b = ${a + b}`;
console.log(f());
console.log(f(8));
console.log(f(,8));
메서드(method); 함수 프로퍼티
- 객체의 프로퍼티인 함수를 메서드(method)라 하고, 일반적인 함수와 구별.
- 객체 리터럴에 메서드 추가 가능.
const dog = {
name: '멍멍이',
sound: '멍멍!',
say: function () {
console.log(this.sound);
},
};
dog.say();
const dog = {
name: '멍멍이',
sound: '멍멍!',
say() {
console.log(this.sound);
},
};
dog.say();
this 키워드
- 화살표 함수에서는
this
키워드 사용 불가. (undefined
출력; 상속되지 않음)
- 함수 바디에서 특별한 읽기 전용 값
this
.
- 메서드를 호출하면
this
는 해당 메서드를 소유하는 객체가 됨.
this
는 함수의 선언이 아닌 호출 방법에 따라 변함.
const dog = {
name: '멍멍이',
sound: '멍멍!',
say() {
console.log(this.sound);
},
};
const cat = {
name: '야옹이',
sound: '야옹~',
};
cat.say = dog.say;
dog.say();
cat.say();
const catSay = cat.say;
catSay();
console.log(dog.say === cat.say && catSay === dog.say && catSay === cat.say);
call 메서드
함수.call(객체 식별자)
- 모든 함수에서 사용 가능.
- 함수를 호출하면서
call
을 사용하여 객체를 넘기면, 객체의 메서드 처럼 this
사용 가능.
const bruce = { name: 'Bruce' };
const madeline = { name: 'Madeline' };
function greet() {
return `Hello, I'm ${this.name}~`;
}
console.log(greet());
console.log(greet.call(bruce));
console.log(greet.call(madeline));
call
의 매개변수가 여러개라면...?
- 함께 호출한 함수와 나눠야 하는데, 첫번째 매개변수만
call
로 사용. (즉 this)
- 첫번째 매개변수를 제외하고는 함께 호출된 함수로 전달됨.
함수.call(객체 식별자, 함수 매개변수)
const bruce = { name: 'Bruce' };
const madeline = { name: 'Madeline' };
function update(birthYear, occupation) {
this.birthYear = birthYear;
this.occupation = occupation;
}
update.call(bruce, 1949, 'singer');
update.call(madeline, 1942, 'actress');
console.log(bruce);
console.log(madeline);
apply 매서드
함수.apply(객체 식별자, [함수 매개변수])
- 매개변수를 배열로 받는 것을 제외하면
call
동일.
const bruce = { name: 'Bruce' };
const madeline = { name: 'Madeline' };
function update(birthYear, occupation) {
this.birthYear = birthYear;
this.occupation = occupation;
}
update.apply(bruce, [1949, 'singer']);
update.apply(madeline, [1942, 'actress']);
console.log(bruce);
console.log(madeline);
const arr = [2, 3, -5, 15, 7];
console.log(Math.min.apply(null, arr));
console.log(Math.max.apply(null, arr));
- 확산 연산자(
...
)를 사용하여 apply
와 같은 결과 얻을 수 있음. (아직 이해못함)
bind 매서드
const bruce = { name: 'Bruce' };
const madeline = { name: 'Madeline' };
function update(birthYear, occupation) {
this.birthYear = birthYear;
this.occupation = occupation;
}
const updateBruce = update.bind(bruce);
updateBruce(1904, 'actor');
console.log(bruce);
updateBruce.call(madeline, 1274, 'king');
console.log(bruce);
- 다만 함수의 동작을 영구적으로 바꾸므로 찾기 어려운 버그 원인이 될 수 있음.
- 함수의
this
가 묶이는 곳을 정확히 한 뒤, 사용해야 유용.