# 함수 특징
출처: https://medium.com/ibare-story/e252506f8525
1. 느슨한 인수 전달 메커니즘: 전달된 인수의 값 검증을 습관화하자
function(x, y) {
if( x == undefined || y == undefined) {
throw new Error("인수 x, y 필요");
}
}
2. 함수 호출시 arguments로 매우 유연하게 가변 인수를 처리한다.
// 전달된 인수의 합을 반환하는 함수
function add() {
var sum = 0;
for( var i = 0; i < arguments.length; i++ ){
sum += ( typeof arguments[i] == 'number' ) ?
arguments[i] : 0;
}
return sum;
}
add(); // 0
add( 10, 20, 30 ) // 60
3. 함수도 객체이며 객체와 같이 속성과 메소드를 가진다
// 아무것도 하지 않는 함수
function empty(x, y) { }
console.log(empty.length); // 2
=> empty 함수의 속성 length에 접근, 함수 인수 사양의 인수 갯수를 나타냄
=> apply, call, bind, name, prototype, toString 등 다양한 속성과 메소드가 있음
4. 언제든지 함수에 속성을 추가할 수 있다.
예제 1)
function foo() { }
foo.location = 'seoul';
console.log(foo.location); // seoul
예제 2)
// 단 한번만 할 일을 하는 게으른 함수 double
function double(x) {
if(!double.isCall) {
double.isCall = true;
} else {
return undefined;
}
return x * x;
}
double(10); // 100
double(20); // undefined
double(30); // undefined
// 다른 방법으로 나타내기
function double(x) {
double = function() {}; // 호출하는 순간 double 함수를 재정의한 후 반환
return x * x;
}
double(10); // 100
double(20); // undefined
double(30); // undefined
// 몇 번 호출됬는지 스스로 기억하는 함수
function double(x) {
if(!double.callCount) {
double.callCount = 1;
} else {
double.callCount++;
}
for( var i=1 ; i<=100 ; i++ ) {
double(i);
}
console.log(double.callCount); // 100
5. 함수 안에 함수를 사용할 수 있다.
// 함수 get을 포함하고 있는 foo 함수
function foo() {
function get() {
return 100;
}
return get();
}
foo(); // 100
6. new로 호출된 함수는 보통의 함수 호출과는 약간 다르다
- 호출된 이후 함수는 완료 됨
- 암묵적으로 만들어진 함수의 인스턴스 반환
- 클래스와 유사한 목적으로 설계된 함수는 구분을 위해 대문자로 시작
7. this는 마치 public 멤버 변수와 유사하게 작동
// 비교 코드
function Foo1() {
var x = 10;
}
function Foo2() {
this.x = 10;
}
var foo1 = new Foo1();
var foo2 = new Foo2();
foo1.x; // undefined
foo2.x; // 10
- Foo1안쪽의 지역변수 x는 인스턴스 생성 기간 동안 존재, 반환과 함께 사라짐
=> 함수 호출 동작 방식과 동일
=> 이미 제거되었기 때문에 인스턴스 foo1에서 참조 불가능
- Foo2의 인스턴스 foo2에서는 x 참조 가능
=> 인스턴스의 실행 컨텍스트를 가리키는 this에 생성되었기 때문
=> 컨텍스트에 작성된 값은 컨텍스트의 라이프 사이클 동안 유지
=> 즉, foo2가 메모리에서 제거되기 전까지 x 값은 유지(public 멤버 변수와 유사하게 작동)
8. 함수의 멤버 함수(메소드)도 this에 추가되어야 인스턴스에서 사용 가능
// 예제
function Foo() {
this.getX = function() {
return 10;
};
function getY() {
return 20;
};
}
var foo = new Foo();
foo.getX(); // 10
foo.getY(); // Error!
9. prototype: 동적으로 속성이나 메소드를 추가 할 수 있다
=> 함수의 모든 인스턴스에 즉시 반영됨
// 예제
function Foo(x) {
this.x = x;
}
var foo1 = new Foo(10);
var foo2 = new Foo(20);
foo1.x; // 10
foo2.x; // 20
foo1.y = 100;
foo1.y; // 100
foo2.y; // undefined
Foo.prototype.z = 1000;
foo1.z; // 1000
foo2.z; // 1000
함수에 직접 추가된 속성은 함수의 생성자로 만들어진 인스턴스에서는 사용할 수 없음을 주의해야한다. 생성자가 만들어낸 인스턴스에서 재새용될 메소드나 속성은 반드시 prototype에 추가한다.
=> ?? 무슨말이지 이해가안되넹.. 찾아볼것
10. 함수호출하는 3가지 방법 - 이름, call, apply
// 예제 1
function foo(x) { };
foo(10);
foo.call(this, 10);
foo.call(this, [10]);
- 함수가 호출될 때 함수에게 전달되는 모든 인수를 담은 arguments 유사 배열과 함께 this도 암시적으로 전달
=> this는 함수를 호출한 컨텍스트를 가르키며 전역 공간에서 호출될 땐 전역 객체를 가르킴
=> ex) 브라우저 환경이라면 window 객체
=> 객체의 메소드로서 함수가 호출되면 this는 객체를 가르킴
// 예제 2
var person = {
age: 10,
addAge: function(n) {
this.age += n;
}
};
person.addAge(1);
console.log(person.age); // 11
- addAge의 this는 암묵적으로 함수 호출시 전달된 객체
=> 객체의 메소드인 경우 객체 그 자체
- this는 person 이라고 설명해도 문제는 없지만 자바스크립트는 this가 지시하는 대상을 변경할 수 있는 유연성을 제공
// 예제 3
var person = {
age: 10,
addAge: function(n) {
this.age += n;
}
};
var monkey = {
age: 1
};
person.addAge.call(monkey, 1);
console.log(person.age); // 10
console.log(person.age); // 2
- 객체 내부에서 사용하는 this가 호출시점의 실행 컨텍스트를 가르키며 이는 함수가 어떻게 호출되는가에 따라 this가 달라질 수 있다는 것
11. apply
- call과 똑같이 동작
- 두번째 인수, 즉 호출할 함수에게 전달할 인수 목록을 배열로 받음
- 호출할 함수가 가변 인수를 받는 함수라면 배열을 전달하는 apply를 사용하면 손쉽게 처리 가능
12. bind
ECMAScript 5 스펙에 추가된 bind 메소드는 함수와 객체를 연결시킴
13. 1급 함수
- 함수도 변수에 할당 가능
=> 함수의 인수로 전달 가능,
=> 함수의 반한값이 될 수 있음
- 변수에 할당된 함수의 호출은 일반적인 함수의 호출과 같은 방식으로 작동
// 예제
// 변수에 할당한 함수
var foo = function foo() { ... } ;
// 변수에 할당된 foo 함수 호출
foo();
14. 이름 없는 익명 함수
- 함수의 이름이 필요 없다면 기술하지 않아도 됨
// 예제 1
// 익명 함수 생성 후 foo 변수에 할당
var foo = fucntion(x) {
return x * x;
};
foo(10); // 100
- 이름없는 익명 함수를 참조하고 있는 foo를 이용하여 마치 foo 라는 함수를 호출하는 것과 같은 방식으로 호출할 수 있음
- 함수는 length 속성 이외에 name 속성도 제공
// 예제 2
var foo1 = function orgFoo() { };
var foo2 = function() { };
console.log(foo1.name); // orgFoo
console.log(foo2.name); // 빈문자열
- 위 코드를 보면 익명 함수는 이름이 없다는 걸 확인 가능
// 예제 3
var foo = {
age: 10,
addAge: funcion() {
this.age++;
}
};
- 위 코드는 객체 foo를 생성하며 addAge 메소드를 작성하며 익명 함수를 사용함
- 이 경우 addAge 속성이 존재함으로 함수의 이름이 불필요하기 때문에 이름이 없는 익명 함수를 사용
15. 즉시 실행 함수
- 익명 함수를 생성과 동시에 즉시 실행 가능
// 예제
(function () {
...
}) ();
-단 한번만 수행되는 초기화 작업 등, 전역 공간의 오염 없이 수행하기 위한 방법으로 많이 사용
16. 지역 유효 범위 생성자로서의 함수
- var 구문 없이 생성된 변수는 전역 변수로 생성 됨
=> 지역 스코프에 존재하지 않고 함수의 수행이 종료된 후에도 전역 스코프에 잔류
=> 메로리 낭비됨
// 예제
functin foo(x) {
sum = x * x;
}
foo(10);
console.log(sum); // 100
// 예제 2
function foo () {
var x = 10;
function getx() {
return x; // 상위 지역 스코프 변수 x를 참조. 10을 반환한다
}
return getx();
}
foo(); // 10
17. 클로저
- 함수와 함수가 접근할 수 있는 주변 환경으로 구성된 특별한 개념
// 예제 1
function multiple() {
var x = 10;
return function(y) {
return y * x;
};
}
var mul = multiple();
mul(10); // 100
mul(5); // 50
- 함수 multiple은 익명 함수를 반환
- 반환되는 익명 함수의 바깥 함수 multiple을 걷어내면 보통의 익명 함수를 할당하는 대입문과 같다
- 지역 변수 x는 multiple을 호출하고 반환해도 존재하며 그 값은 익명 함수가 반환되는 시점의 x값인 1이다
=> 이것이 클로저!!
// 예제 2 : 클로저 패턴을 사용하면 새로운 함수를 동적으로 생성 가능
function multiple(x) {
return function(y) {
return y * x;
};
}
var mul10 = multiple(10);
var mul5 = multiple(5); // 50
var mul10 = multiple(10); // 100
var mul100 = multiple(100); // 1000
mul5(10); // 50
mul10(10); // 100
// 예제 3 : 클로저의 특징을 이용하면 private 변수를 흉내 낼 수 있다
function Person (name, age) {
this.getName = function() {
return name;
};
this.getAge = function() {
return age;
};
this.addAge = function() {
age++;
};
}
var person = new Person('홍길동', 5);
person.getName(); // 홍길동
person.getAge(); // 5
person.name; // undefined
person.addAge();
person.getAge(); // 6
18. 콜백 함수
- 자바스크립트의 함수는 1급 함수로서 변수에 할당 가능
=> 함수를 함수의 인수로 전달할 수 있다는 의미
- 함수의 호출이 비동기 방식으로 작동되어야 할 때 이 콜백 함수를 이용
// 예제1 : 타이머에 의한 함수 호출
var cont = 1;
function sayHello () {
console.log("Hello?", count);
count++;
}
// 첫번째 인수로 함수를 전달
// setTimeout은 호출과 함께 즉시 제어권을 반환
// 1000ms 후에 sayHello를 호출
setTimeout(sayHello, 100);
sayHello(); // "Hello? 1" 출력. 10초 후 "Hello? 2" 출력
- 인수로 받은 함수를 콜백 함수라 함
=> 특정 시간 이후에 호출되어야 하거나,
=> 네트워크 자원을 호출하여 반환값을 받는것,
=> 특정 이벤트가 발생했을 때 호출되어야 하는 함수(이벤트 핸들러)와 같이 함수 호출의 시기를 호출하는 시점에 특정할 수 없을때
콜백 함수 패턴이 유용하게 쓰임
// 예제 2
var saveButton = document.getElmentById("save");
// click 이벤트가 발생했을 때 saveDocument 함수가 호출
saveButton.addEventListener("click", saveDocument);
19. 콜백 지옥
- 간단한 비동기 작업은 콜백 패턴이 좋다
- 비동기 작업이 중첩되는 상황에서는 nono
// 예제 3개의 비동기 콜백이 중첩된 코드
ayncJob (function(err, step1Data) {
ayncJobInner(function(err, step2Data) {
ayncJobDeepInner(function(err, step3Data) {
// create step4Data
});
});
});
- 백앤드 자바스크립트인 node 어플리케이션에서 콜백과 콜백이 중첩되는 상황 자주 발생
=> 비동기가 중첩된 흐름 제어는 콛의 가독성을 떨어뜨리고
=> 테스트를 어렵게 만든다
20. 흐름 제어 라이브러리
- 비동기 콜백과 흐름 제어(병렬 실행, 순차 실행)를 구현하기 위해 중첩된 콜백을 사용하지 않아도 되는 여러 대안 라이브러리가 존재함
1) async https://github.com/caolan/async
2) step https://github.com/creationix/step
3) q https://github.com/kriskowal/q
4) when https://github.com/cujojs/when
5) RSVP https://github.com/tildeio/rsvp.js
21. Promise & Generator
- 비동기 흐름 제어 코드를 직관적이고 아름답게 작성할 수 있도록 지원하는 자바스크립트의 네이티브 구현
=> ES 6 스펙으로 구현
=> 최신 브라우저와 node에서 동작
=> 자세한 내용은 아래 링크 참조
* JavaScript Promises
http://www.html5rocks.com/en/tutorials/es6/promises/
http://www.html5rocks.com/ko/tutorials/es6/promises/