[Effective JavaScript] 절대 arguments 객체를 수정하지 마자

김범식·2023년 7월 4일
0

Effective JavaScript

목록 보기
3/33
post-thumbnail

arguments 객체가 배열과 비슷해 보일수 있으나 배열처럼 동작하지 않는다. 예를 들어 shift() 라는 함수가 있는데, 이 메서드는 배열의 첫번째 요소를 젝하고 뒤이은 모든 요소들을 하나씩 이동시킨다.

var fruits = ["apple", "banana", "orange"];

var firstFruit = fruits.shift();

console.log(firstFruit); // 출력: "apple"
console.log(fruits); // 출력: ["banana", "orange"]

arguments에서는 이 shift() 를 사용할 수 없다. Array타입이 아니기 때문이다.



그렇다면 call 메서드를 사용해서 shift함수를 추출해 arguments 객체에 호출할 수 있지 않을까 ? 다음 예제를 살펴보자

function callMethod(obj, method){
	var shift = [].shift; // 함수를 변수에 저장

	// arguments 객체에 shift 사용
	shift.call(arguments); //obj 제거
	shift.call(arguments); //method 제거 

	return obj[method].apply(obj, arguments);
}



하지만 이 함수는 제대로 동작하지 않는다.

var obj = {
	add : function(x,y) { return x+y;}
};
callMethod(obj, "add", 17,25); 
//오류 정의되지 않은 apply 프로퍼티 읽을 수 없음 



이 함수에tj 오류가 발생하는 이유는 arguments 객체가 함수의 arguments의 복사물이 아니기 때문이다. 이게 무슨 말이냐면 objmethod를 지운다면 obj17이 들어가고 method25가 들어가게 되어 결과적으로 obj[method] 가 아닌 17[25] 가 나오게 된다. 그리고 두개를 다 지워버린 arguments에는 여전히 27 15가 들어있게 된다. 때문에 apply 프로퍼티를 추출하려는 시도는 실패하게 된다.

arguments 객체를 수정하면 지정된 파라미터 값이 달라진다는 말이다.



strict 모드를 사용하면 더욱 불안정해진다.

function strict(x){
	"use strict"
	arguments[0] = 'modified'
	return x == arguments[0];
}
function nonStrict(x){
	arguments[0] = 'modified'
	return x == arguments[0];
}
strict("unmodified") //false
nonstrict("unmodified") //true

스트릭트 모드에서 함수 파라미터는 자신의 arguments 객체를 별명으로 삼지 않는다.

때문에 arguments 객체를 수정하는건 안하는게 좋다. 정 하고 싶다면 배열의 복사본을 만들어서 사용하면 된다.



관례적으로 다음과 같은 코드를 사용한다.

var args = [].slice.call(arguments)



이전 코드를 관례를 사용하여 변경해보자

// slice를 사용한 배열 복사

function callMethod(obj, method){
	var args = [].slice.call(arguments,2);  //일정 인자 뒤로 전부 가변인자로 사용한다. 
	return obj[method].apply(obj, args);   //가변인자가 배열로 들어오기 때문에 가변인자로 받을 수 있게 apply로 변경함
}
  • 예시에서는 2번째 매개변수 이후로는 전부 가변인자로 사용할 수 있다.
  • 가변인자가 배열로 들어오기 때문에 가변인자로 사용할 수 있도록 apply로 받아왔다.
var obj = {
	add : function(x,y) { return x+y;}
};
callMethod(obj, "add", 17,25);  // 42 출력

이제 잘 동작한다.



기억할 점

  • arguments 객체를 절대 수정하지 마라
  • arguments 객체를 수정하기 전에 [].slice.call(arguments)를 호출해 진짜 배열로 복사하라
profile
frontend developer

0개의 댓글