Recent Posts
Recent Comments
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Tags
more
Today
Total
관리 메뉴

고리타분한 개발자

함수 (Function) - arguments 객체 본문

JavaScript/Garden

함수 (Function) - arguments 객체

sunlee334 2017. 11. 10. 04:37

Javascript의 모든 함수 스코프에는 arguments라는 특별한 변수가 있습니다. 이 변수는 함수에 넘겨진 모든 인자에 대한 정보가 담겨있습니다.


arguments 객체는 Array가 아닙니다. 물론 length 프로미터도 있고 여러므로 Array와 비슷하게 생겼지만 Array.prototype을 상속받지는 않습니다.


그래서, arguments에는 push, pop, slice같은 표준 메소드가 없습니다. 일반 for문을 이용하여 순회할 수는 있지만, Array의 메소드를 이용하려면 arguments를 Array로 변환해야 합니다.


Array로 변환하기


다음 코드는 arguments에 있는 객체를 새로운 Array에 담아 반환합니다.


Array.prototype.slice.call(arguments);


이 변환 과정은 느리기 때문에 성능이 중요한 부분에서는 사용하는것이 바람직 하지 않습니다.


arguments 변수는 Function 안에서 다시 정의할 수 없습니다. var 구문이나 파라미터에 arguments라는 이름으로 변수를 정의해도 변수가 재정의 되지 않습니다.


arguments 객체 넘기기


어떤 함수에 다른 함수로 arguments 객체를 넘길 때에는 다음과 같은 방법을 권합니다.


function monkey() {
animal.apply(null, arguments);
}

function animal(a, b, c) {

}


또 다른 트릭은 call과 apply를 함깨 사용하여 메써드(this의 값과 인자들을 사용하는 함수)를 단지 인자들만 사용하는 일반 함수로 바꾸는 것입니다.


function Person(first, last) {
this.first = first;
this.last = last;
}

Person.prototype.fullname = function(joiner, options) {
options = options || {
order: "western"
};
var first = options.order === "western" ? this.first : this.last;
var last = options.order === "western" ? this.last : this.first;
return first + (joiner || " ") + last;
};

// "fullname" 메써드의 비결합(unbound) 버전을 생성한다.
// 첫번째 인자로 'first'와 'last' 속성을 가지고 있는 어떤 객체도 사용 가능하다.
// "fullname"의 인자 개수나 순서가 변경되더라도 이 랩퍼를 변경할 필요는 없을 것이다.
Person.fullname = function() {
// 결과: Person.prototype.fullname.call(this, joiner, ..., argN);
return Function.call.apply(Person.prototype.fullname, arguments);
};

var grace = new Person("Grace", "Hopper");

// 'Grace Hopper'
grace.fullname();

// 'Turing, Alan'
Person.fullname({
first: "Alan",
last: "Turing"
}, ", ", {
order: "eastern"
});


일반 파라미터와 arguments 객체의 인덱스


일반 파라미터와 arguments 객체의 프로퍼티는 모두 getter과 setter를 가집니다. 그래서, 파라미터나 arguments 객체의 프로퍼티의 값을 바꾸면 둘 다 모두 바뀌게 됩니다.


function monkey(a, b, c) {
arguments[0] = 2;
a; // 2

b = 4;
arguments[1]; // 4

var d = c;
d = 9;
c; // 3
}
monkey(1, 2, 3);


성능

arguments 객체는 항상 만들어지지만 두가지 예외사항이 있습니다. arguments라는 이름으로 변수를 함수 안에 정의하거나 arguments 객체로 넘겨받는 인자중 하나라도 정식 인자로 받아서 사용하면 arguments 객체는 만들어지지 않습니다. 하지만, 이런 경우들은 arguments 객체를 안쓰겠다는 의미로 신경쓰지 않아도 됩니다. 

그리고, getter와 setter는 항상 생성되기 때문에 getter/setter를 사용하는 것은 성능에 별로 영향을 끼치지 않습니다. (strict 모드에서는 getter과 settlr가 생성되지 않습니다.) 그러나, arguments.callee를 사용하면 성능이 떨어지게 됩니다.

function monkey() {
arguments.callee; // 이 함수를 가리킨다.
arguments.callee.caller; // 이 함수를 호출한 부모함수를 가리킨다.
}

function bigLoop() {
for (var i = 0; i < 100000; i++) {
monkey();
}
}

위 코드에서 monkey 함수는 자기 자신을 호출한 함수를 알아야 하기 때문에 더이상 인라인 되지 않습니다. 이렇게 쓰면 인라인이 주는 성능상 장점을 포기하여야 하고 이 함수가 호출되는 상황(calling context)에 의존하여야 하기때문에 캡슐화(Encapsulation)도 해칩니다.

arguments.callee와 arguments.callee의 프로퍼티들은 사용하지 않는것이 좋습니다. strict 모드에서 arguments.callee는 deprecated됐기 때문에 사용하면 TypeError가 납니다.


License

이 게시글은 JavaScript Garden을 참고하여 작성 되었습니다. (https://github.com/BonsaiDen/JavaScript-Garden)







Comments