함수

함수 정의

함수를 정의(define)하는 방법은 여러 가지가 있습니다. 함수 선언(function declaration, or function definition, for function statement)을 이용하는 방법과 함수 표현식(function expression), 화살표 기호를 이용하는 방법 등이 있습니다.

함수 선언(function declaration)

함수 선언을 통해 함수를 정의하는 방법은 다음과 같습니다.

function 함수이름(매개변수1, 매개변수2, ..., 매개변수N) {
      ...생략...
}

선언 함수는 다음과 같이 사용합니다.

function 함수() {
    console.log('매개변수:', )
}

함수('매개변수입니다.')

위의 결과는 다음과 같습니다.

매개변수: 매개변수입니다.

반환값

함수 호출의 반환값은 return을 이용합니다. return 문이 없으면 undefined를 반환합니다.

호출과 참조

자바스크립트는 함수도 객체입니다. 따라서 함수를 다른 변수에 할당할 수 있고 함수의 매개변수로 넘길 수 있으며 함수의 반환값으로 함수를 넘길 수 있습니다.

함수를 호출할 때는 항상 소괄호를 이용합니다.

function getGreeting() {
  return "Hello World";
}

getGreeting();

다음과 같이 함수를 다른 변수에 할당할 수 있습니다.

const f = getGreeting;
f(); // "Hello World"

함수를 객체 프로퍼티에 할당할 수 있습니다.

const o = {};
o.f = getGreeting;
o.f(); // "Hello World"

배열 요소로도 할당할 수도 있습니다.

const arr = [1, 2, 3];
arr[1] = getGreeting;
arr[1](); // "Hello World"

함수 표현식(function expression)

함수 표현식이란 함수 선언과 다르게 function 키워드 앞에 뭔가가 있습니다. 함수 표현식은 호이스팅(hoisting)이 되질 않습니다. 다음과 같은 예를 들 수 있습니다.

// 함수 이름이 없는 함수 표현식
let fn = function() {
}

// 함수 이름이 있는 함수 표현식
let fn = function fun_name() {
}

// 즉시 호출하는 함수(IIFE)
(function(a, b) {
  return a + b;
})(1, 2)

익명 함수(anonymous function)

함수의 이름이 없는 함수를 익명 함수라고 합니다.

function([매개변수]) {
    ...생략...
}

함수는 객체이기 때문에 변수에 할당해서 사용할 수 있습니다.

var  = function(매개) {
    console.log('매개변수:', 매개);
}

('매개변수입니다.');

익명 함수를 이라는 변수에 할당해서 함수를 호출하고 있는 것을 알 수 있습니다.

익명 함수는 주로 클로저(closure) 또는 다른 함수의 인자로 사용됩니다.

함수의 매개변수

함수의 매개변수로 원시 타입이 건네 줄 때 원시 타입의 값은 복사가 되서 넘겨집니다. 하지만 객체가 인자로 넘겨질 때는 객체 자체가 넘겨져 함수 안에서 객체가 변경되면 함수 호출 후에도 변경된 값이 유지됩니다.

function f(o) {
  o.message = `f 안에서 수정함(이전 값: '${o.message}'`;
}

let o = {
  message: '초기값',
}

console.log(`f를 호출하기 전: o.message="${o.message}"`);
f(o);
console.log(`f를 호출한 다음: o.message="${o.message}"`);

실행한 결과는 다음과 같습니다다.

f를 호출하기 : o.message="초기값"
f를 호출한 다음: o.message="f 안에서 수정함(이전 값: '초기값'"

매개변수 기본값

매개변수에 기본값을 지정하는 것도 가능합니다.

function f(a, b=10, c="default") {
  console.log("a:", a, "b:", b, "c:", c);
}

객체의 프로퍼티인 함수

앞에서보 언급했듯이 객체의 프로퍼티로 함수를 취할 수 있는데 이 함수를 메소드라고 부릅니다.

const o = {
  name: "Mike",
  bark: function() {return "Woof";},
}

this 키워드

일반적으로 this는 객체의 프로퍼티인 메소드에서 의미가 있습니다. 메소드를 호출하면 this는 호출한 메소드를 소유하는 객체를 의미합니다.

const 명함 = {
  이름: "길동",
  이름은() {return `내 이름은 ${this.이름}입니다.`},
}

명함.이름은()을 호출하면 this가 가리키는 것은 이름은() 메소드를 소유하고 있는 객체인 명함이 됩니다. 따라서 다음과 같은 결과가 나옵니다.

console.log(명함.이름은()); // "내 이름은 길동입니다"

다음을 보면 호출하는 객체에 따라 다른 결과가 나오는 것을 알 수 있습니다.

const 이름은 = 명함.이름은;
console.log(이름은()); // "내 이름은 undefined입니다."

이름은() 메소드를 소유하고 있는 객체가 없기 때문에 this가 가리키는 것이 없게 되어 undefined가 나오게 됩니다.

클로저(closure)

클로저

프라미스(Promise)

Promise 개체는 비동기 작업이 맞이할 미래의 완료 또는 실패와 그 결과 값을 나타냅니다.

프라미스 정의는

let promise1 = new Promise((resolve, reject) => {
  // resolve 또는 reject 구현
  resolve('반환값')
  // 또는
  reject('오류값')
})

첫 번째 함수(resolve)는 비동기 작업이 성공적으로 완료되어 결과를 값으로 반환하면 호출되고, 두 번째 함수(reject)는 작업이 실패하여 오류의 원인을 반환하면 호출됩니다. 두 번째 함수는 주로 오류 객체를 받습니다. resolve 또는 reject의 반환값이 없으면 계속 대기 상태가 유지됩니다.

프라미스 실행은

// resolve  
promise1.then((result) => {
  ...
})
// 또는 reject  때는
promise1.catch((res) => {
  ...
})

result는 promise1의 상태가 완료(resolve)가 발생했을 때 결과값이 result로 전달되어 실행됩니다.

프라미스가 한번 결정되면 더 이상 결정은 이루어지지 않습니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
/**
 * 프라미스가 한 번 결정(resolved)되면 더 이상의 결정은 일어나지 않습니다.
 */

p2 = new Promise((resolve, reject) => {
  // resolve(new Date());
  console.log("start at: ", new Date());
  setTimeout(() => resolve(new Date()), 1000);
});

p2.then((res) => {
  console.log("first then: ", res);
});

p2.then((res) => {
  console.log("next then: ", res);
});

result = p2.then((res) => res);
console.log("result: ", result);

위 코드를 실행시키면 다음과 같이 나옵니다.

start at:  2019-06-23T12:18:40.700Z
result:  Promise { <pending> }
first then:  2019-06-23T12:18:41.709Z
next then:  2019-06-23T12:18:41.709Z
  1. 제일 먼저 5라인 프라미스 객체가 만들어지면서 7라인이 실행됩니다.
  2. 8라인이 실행되면서 1초 후에 resolve가 실행되도록 예약을 합니다.
  3. 11, 15 라인이 실행이 되려고 하지만 아직 1초가 지나지 않았으므로 프라미스의 상태가 결정되지 않아 보류를 하고 넘어 갑니다.
  4. 19라인도 1초가 지나지 않은 상태이므로 프라미스의 then을 실행하지 않고 result에는 p2의 상태인 Promise { <pending> }을 넘겨주게 됩니다.
  5. 20라인이 실행되면 Promise { <pending> }이라는 메시지가 출력이 되면서 아직 대기(pending) 상태라는 것이 찍힙니다.
  6. 1초가 지나면 드디어 프라미스의 상태가 이행(resolved)으로 변경되어 11, 15 라인이 작동이 되면서 시각을 출력하게 됩니다. 그런데 같은 값을 출력하는 볼 수 있습니다. 이것은 프라미스가 한번 이행이 되면 더이상 반복해서 이행이되질 않는 것을 알 수 있습니다.

프라미스의 then, catch에 의해서 반환된 값도 역시 프라미스이므로 계속 연결(chaining)해서 사용할 수 있습니다.

컨텍스트(Context)

zero cho의 컨텍스트

함수 안에서 this

poiemaweb this 참조

function 으로 정의한 함수를 일반함수라고 하고 화살표 =>로 정의한 함수를 화살표함수(arrow function)이라고 부르겠습니다.

일반함수의 this와 화살표함수의 this는 다르게 동작합니다. 생성자함수객체의 메소드를 제외한 모든 함수(내부 함수, 콜백 함수 포함) 내부의 this는 전역 객체를 가리킵니다.

일반함수의 this

자바스크립트의 경우 함수 호출 방식에 의해 this에 바인딩할 어떤 객체가 동적으로 결정됩니다. 다시 말해, 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정되는 것이 아니고, 함수를 호출할 때 함수가 어떻게 호출되었는지에 따라 this에 바인딩할 객체가 동적으로 결정됩니다.

콜백 함수 내부의 this는 전역 객체 window를 가리킵니다.

화살표함수의 this

화살표함수는 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정됩니다. 동적으로 결정되는 일반 함수와는 달리 화살표함수의 this는 언제나 상위 스코프의 this를 가리킵니다. 이를 Lexical this라고 합니다.

참조