함수
// sayHello라는 함수를 선언
function sayHello() {
//함수 바디는 여는 중괄호로 시작하고
console.log("hello World");
//닫는 중괄호로 끝난다.
}
// 함수를 호출
sayHello(); //hello World
반환값
- return 키워드를 사용하면 함수를 종료하고 값을 반환한다.
- return을 명시적으로 호출하지 않으면 반환 값은 undefined가 된다.
function sayHello() {
return "hello World";
}
sayHello(); //hello World
호출과 참조
- 함수 식별자 뒤에 괄호를 쓰면 함수를 호출하고 함수의 표현식은 반환 값이 된다.
- 괄호를 쓰지 않으면 다른 값과 마찬가지로 함수를 참조하고 함수를 실행하지 않는다.
sayHello(); //hello World
sayHell; //function sayHello()
- 함수를 변수에 할당하면 다른 이름으로 함수를 호출할 수 있다.
const f = sayHello;
f(); //hello World
- 함수를 객체 프로퍼티에 할당할 수도 있다.
const o = {};
o.f = sayHello;
o.f(); //hello World
- 배열요소로 할당할 수 있다.
const arr = [1,2,3];
arr[1] = sayHello; //arr은 [1, function sayHello(), 2]
arr[1](); //hello World
함수와 매개변수
//a와 b를 정해진 매개변수라고 한다.
//함수가 호출되면 정해진 매개변수는 값을 받아 실제 매개변수가 된다.
function avg(a, b) {
return (a+b)/2;
}
function f(o) {
o.message = "f에서 수정함";
o = {
message : "새로운 객체"
};
console.log(`f 내부 : ${o.message}`)
}
let o ={
message : '초기값'
};
console.log(`f 호출 전 : ${o.message}`);
f(o);
console.log(`f 호출 후 : ${o.message}`);
==출력
f 호출 전 : 초기값
f 내부 : 새로운 객체
f 호출 후 : f에서 수정함
//함수 내부의 매개변수 o와 함수 바깥의 변수 o가 다르다.
//f를 호출하면 둘은 같은 객체를 가리키지만, f내부에서 o에 할당한 객체는 새로운 객체이다.
매개변수 해체
- 프로퍼티 이름은 반드시 유효한 식별자여야 한다.
- 들어오는 객체에 해당 프로퍼티가 없는 변수는 undefined를 할당.
function getSentence({subject, verb, object}) {
return `${subject} ${verb} ${object}`;
}
const o = {
subject : "I",
verb : "love",
object : "Javascript",
};
getSentence(o); //I love Javascript
- 배열도 해체할 수 있다.
function getSentence([subject, verb, object]) {
return `${subject} ${verb} ${object}`;
}
const o = ["I", "love", "Javascript"];
getSentence(o); //I love Javascript
- 확산 연산자(…) 써서 남는 매개변수를 이용할 수 있다.
- 함수를 선언할 때 확산 연산자는 반드시 마지막 매개변수여야 한다.
function addPrefix(prefix, ...words) {
const prefixedWords = [];
for(let i=0; i<words.length; i++) {
prefixedWords[i = prefix + words[i]
}
return prefixedWords;
}
addprefix("con", "verse", "vex"); // ["convers", "convex"];
매개변수 기본값
- ES6에서는 매개변수에 기본값을 지정하는 기능이 추가되었다.
function f(a, b="default", c=3) {
ruetnr `${a} - ${b} - ${c}`;
}
f(5, 6, 7); //"5 - 6 - 7"
f(5, 6); //"5 - 6 - 3"
f(5); //"5 - default - 3"
f(); //"undefiend - default - 3"
객체의 프로퍼티인 함수
- 객체의 프로퍼티인 함수를 메소드라고 불러서 일반적인 함수와 구별한다.
- 객체 리터럴에서도 메서드를 추가할 수 있다.
cost o = {
name : "Wallace", //원시 값 프로퍼티
bark : function() { return 'Woof'; } //함수 프로퍼티(메소드)
}
//ES6에서 간편하게 추가할 수 있는 문법
cost o = {
name : "Wallace", //원시 값 프로퍼티
bark() { return 'Woof'; } //함수 프로퍼티(메소드)
}
this키워드
- 일반적으로 this는 객체의 프로퍼티인 함수에서 의미가 있다.
- 메서드를 호출하면 this는 호출한 메서드를 소유하는 객체가 된다.
function o = {
name : 'Wallace',
speak() { return 'My name is ${this.name}!'},
}
o.speak(); //My name is Wallace!
- this는 함수를 어떻게 선언했느냐가 아니라 어떻게 호출했느냐에 따라 달라진다.
function o = {
name : 'Wallace',
speak() { return 'My name is ${this.name}!'},
}
cost speak = o.speak;
speak === o.speak; //true; 두 변수는 같은 함수를 가리킨다.
speak(); //My name is undefined!
- 중첩된 함수안에서 this를 사용할 때 문제점 및 해결방법.
cost o = {
name : 'Julie',
greetBackwards : function() {
function getReverseName() {
let nameBackwards = '';
for(let i=this.name.length-1; i>=0; i--) {
nameBackwards += this.name[i];
}
return nameBackwards;
}
return `${getReverseName()} si eman ym ,olleH`;
}
};
//o.greetBackwards()를 호출하는 시점에서는 this가 o에 연결
//greetBackwards안에서 getReversename을 호출하면 this는 o가 아닌 다른 것에 묶임.
o.greetBackwards();
//해결방법은 다른변수에 this를 할당한다.
cost o = {
name : 'Julie',
greetBackwards : function() {
cost self = this;
function getReverseName() {
let nameBackwards = '';
for(let i=self.name.length-1; i>=0; i--) {
nameBackwards += self.name[i];
}
return nameBackwards;
}
return `${getReverseName()} si eman ym ,olleH`;
}
};
o.greetBackwards();
함수 표현식과 익명 함수
- 익명함수에서는 함수에 식별자가 주어지지않는다.
- 함수 표현식은 함수 이름을 생략할 수 있다는 점을 제외하면 함수 선언과 같다.
const f = function() {
// ...
}
- 함수 표현식에서 함수에 이름을 정하고 다시 변수에 할당할 경우.
//이름 g에 우선순위가 있다.
//함수 바깥에서 함수에 접근할 때는 g를 써야하며, f로 접근불가.
const g = function f() {
// ...
}
- 함수 안에서 자신을 호출할 때(재귀) 이런 방식이 필요하다.
//함수안에서는 f를 써서 자기 자신을 참조
//함수 바깥에서는 g를 써서 함수를 호출
const g = function f(stop) {
if(stop) console.log('f stop');
f(true);
};
g(false);
- 나중에 호출할 생각으로 함수를 만든다면 함수 선언을 사용.
- 다른 곳에 할당하거나 다른 함수에 넘길 목적으로 함수를 만든다면 함수 표현식을 사용.
화살표 표기법
- function이라는 단어와 중괄호 숫자를 줄이려고 고안된 단축 문법이다.
- function을 생략해도 된다.
- 함수에 매개변수가 단 하나 뿐이라면 괄호(())도 생략할 수 있다.
- 함수 바디가 표현식 하나라면 중괄호와 return 문도 생략할 수 있다.
- function을 생략해도 된다.
- 화살표 함수는 항상 익명이다. 익명함수를 만들어 다른 곳에 전달하려 할 때 유용하다.
const f1 = function() {return "hello!"; }
//또는
const f1 = () => "hello!";
const f2 = function(name) { return `Hello, ${name}!`; }
//또는
const f2 = name => `Hello, ${name}`;
const f3 = function(a,b) { return a+b; }
//또는
const f3 = (a,b) => a + b;
- this가 다른 변수와 마찬가지로, 정적으로 묶인다.
- 화살표 함수를 사용하면 내부 함수 안에서 this를 사용할 수 있다.
cost o = {
name : 'Julie',
greetBackwards : function() {
cost getReverseName = () => {
let nameBackwards = '';
for(let i=this.name.length-1; i>=0; i--) {
nameBackwards += this.name[i];
}
return nameBackwards;
}
return `${getReverseName()} si eman ym ,olleH`;
}
};
o.greetBackwards();
call과 apply, bind
call
- call 메서드는 모든 함수에서 사용할 수 있으며, this를 특정 값으로 지정할 수 있다.
const bruce = {name:"Bruce"};
const madeline = {name:"Madeline"};
//이 함수는 어떤 객체에도 연결되지 않았지만 this를 사용한다.
function greet() {
ruetnr `Hello I'm ${this.name}!`;
}
greet(); //"Hello, I'm undefined!" - this는 어디에도 묶이지 않음.
greet.call(bruce); //"Hello, I'm Bruce!" - this는 Bruce.
greet.call(madeline); //"Hello, I'm Madeline!" - this는 madeline.
- 함수를 호출하면서 call을 사용하고, this로 사용할 객체를 넘기면 해당 함수가 주어진 객체 메서드인 것처럼 사용할 수 있다.
- call의 첫 번째 매개변수는 this로 사용할 값이고, 매개변수가 더 있으면 그 매개변수는 호출하는 함수로 전달된다.
function update(birthYear, occupation) {
this.birthYear = birthYear;
this.occupation = occupation;
}
update.call(bruce, 1949, 'singer');
//bruce는 이제 {name:bruce, birthYear:1949, occupation:singer};
apply
- apply는 함수 매개변수를 처리하는 방법을 제외하면 call과 같다.
- apply는 매개변수를 배열로 받는다.
function update(birthYear, occupation) {
this.birthYear = birthYear;
this.occupation = occupation;
}
update.call(bruce, [1949, 'singer']);
//bruce는 이제 {name:bruce, birthYear:1949, occupation:singer};
- apply는 배열 요소를 함수 매개변수로 사용해야 할 때 유용한다.
const arr = [2, 3, -5, 15, 7];
Math.min.apply(null, arr); //최솟값 -5
Math.max.apply(null, arr); //최댓값 15
binde
- binde를 사용하면 함수의 this 값을 영구히 바꿀 수 있다.
//update메서드를 이리저리 옮기면서도 호출할 때 this값은 항상 bruce가 되게끔,
//call이나 apply, 다른 bind와 함께 호출하더라도 this 값이 bruce가 되도록 할 때.
const updateBruce = update.binde(bruce);
updateBruce(1904, "actor");
//bruce는 이제 {name:bruce, birthYear:1904, occupation:actor};
updateBruce(maeline, 1274, "king");
//bruce는 이제 {name:bruce, birthYear:1274, occupation:king};
// madeline은 변하지 않는다.
- bind는 매우 유용하지만, 함수의 this가 어디에 묶이는지 정확히 파악하고 사용해야한다.
- bind에 매개변수를 넘기면 항상 그 매개변수를 받으면서 호출되는 새 함수를 만드는 효과가 있다.
//bruce가 태어난 해를 항상 1949로 고정하지만, 직업은 바꿀수 있는 업데이트 함수 구현
const updateBruce1949 = update.bind(bruce, 1949);
updateBruce1949("singer, songwriter");
//bruce는 이제 {name:bruce, birthYear:1949, occupation:singer, songwriter};