함수 (Functions)
JavaScript에서, 함수는 다른 객체처럼 속성 및 메서드를 가질 수 있기에 일급(first-class) 객체입니다. 다른 객체와 함수를 구별하는 것은 함수는 호출될 수 있다는 것입니다. 간단히 말해, 함수는 Function 객체입니다.
일급 시민(first-class citizens)
- 변수나 데이터에 할당할 수 있어야 한다.
- 객체의 인자로 넘길 수 있어야 한다.
- 객체의 리턴값으로 리턴할 수 있어야 한다.
/* 함수 'myFunc' 선언 */
function myFunc(theObject) {
theObject.brand = "Toyota";
}
/*
* 변수 'mycar' 선언;
* 새 객체를 만들고 초기화;
* 'mycar'에 객체 참조를 할당
*/
var mycar = {
brand: "Honda",
model: "Accord",
year: 1998
};
/* Logs 'Honda' */
console.log(mycar.brand);
/* 객체 참조를 함수에 전달 */
myFunc(mycar);
/*
* 함수에 의해 바뀌었기에 객체의
* 'brand' 속성의 값으로 'Toyota' 출력.
*/
console.log(mycar.brand);
arguments 객체
- arguments : 현재 실행 중인 함수에 전달된 인수를 포함하는 배열 같은 객체
- arguments.callee : 현재 실행 중인 함수
ECMAScript 제5판(ES5) 은 엄격 모드에서 arguments.callee()의 사용을 금합니다. function 식(expression)에 이름을 주거나 함수 자체를 호출해야 하는 곳에 function 선언을 사용하여 arguments.callee() 사용을 피하세요.
- arguments.caller : 현재 실행 중인 함수를 호출한 함수
이전의 arguments.caller 속성은 현재 실행한 함수를 적용하여 제공했었습니다. 이 속성은 >삭제되었으며 더 이상 작동하지 않습니다
- arguments.length : 함수에 전달된 인수의 수
arguments
function foo(...args) {
return arguments;
}
foo(1, 2, 3); // { "0": 1, "1": 2, "2": 3 }
function bar(a=1) {
arguments[0] = 100;
return a;
}
bar(10); // 10
function zoo(a) {
arguments[0] = 100;
return a;
}
zoo(10); // 100
callee
// 유명(named) 함수 식 사용
function factorial (n) {
return !(n > 1) ? 1 : factorial(n - 1) * n;
}
[1,2,3,4,5].map(factorial);
// callee 사용
[1,2,3,4,5].map(function (n) {
return !(n > 1) ? 1 : arguments.callee(n - 1) * n;
});
callee보다 유명(named) 함수 식을 사용하자.
- 함수는 코드 내부에서 다른 함수처럼 호출될 수 있습니다
- 외부 범위(outer scope)에서 변수를 만들지 않습니다 (IE 8 아래는 제외하고)
- arguments 객체에 액세스하는 것보다 성능이 더 낫습니다
getter와 setter
- get : 객체 속성을 그 속성이 검색되는 경우 호출되는 함수에 바인딩합니다.
- 숫자나 문자열로 구성된 식별자를 이용할 수 있습니다.
- getter는 절대로 매개변수를 가져서는 안 됩니다. (Incompatible ES5 change: literal getter and setter functions must now have exactly zero or one arguments 를 참조하세요.)
- 하나의 객체 리터럴에 또다른 getter나 데이터 바인딩은 불가능합니다. ({ get x() { }, get x() { } } 나 { x: …, get x() { } } 는 사용할 수 없습니다.)
- set : 객체 속성을 그 속성을 설정하려는 시도가 있는 경우 호출되는 함수에 바인딩합니다.
get
var log = ['test'];
var obj = {
get latest () {
if (log.length == 0) return undefined;
return log[log.length - 1]
}
}
console.log (obj.latest); // "test"를 반환.
// delete연산자를 이용해 getter 삭제하기
delete obj.latest;
set
var language = {
set current(name) {
this.log.push(name);
},
log: []
}
language.current = 'EN';
console.log(language.log); // ['EN']
language.current = 'FA';
console.log(language.log); // ['EN', 'FA']
// delete연산자를 이용해 setter 삭제하기
delete o.current;
블록 레벨 함수
- ES2015 (ES6)를 시작으로 엄격 모드에서, 블록 내부 함수는 이제 그 블록 범위가 됩니다. ES6 이전에, 블록 레벨 함수는 엄격 모드에서 금지됐습니다.
'use strict';
function f() {
return 1;
}
{
function f() {
return 2;
}
}
f() === 1; // true
// 비엄격 모드에서는 f() === 2
비엄격 코드에서 블록 레벨 함수
- 한 마디로: 안됩니다. 비엄격 코드에서, 블록 내부 function 선언은 이상하게 동작합니다.
if (shouldDefineZero) {
function zero() { // 위험: 호환성 위험
console.log("This is zero.");
}
}
-
ES2015는 shouldDefineZero가 false인 경우, 그러면 zero는 결코 정의되어서는 안된다고 합니다, 그 블록이 실행된 적이 없기에. 그러나, 이는 표준의 새로운 일부입니다. 역사상, 이는 지정되지 않은 채 방치되었고 일부 브라우저는 블록이 실행됐든 아니든 zero를 정의할 겁니다.
-
엄격 모드에서, ES2015를 지원하는 모든 브라우저는 이를 같은 식으로 다룹니다: zero는 shouldDefineZero가 true이고 if 블록 범위인 경우에만 정의됩니다.
-
조건부 함수를 정의하는 더 안전한 방법은 function 식을 변수에 할당하는 것입니다
var zero;
if (0) {
zero = function() {
console.log("This is zero.");
};
}