티스토리 뷰

자바스크립트의 함수는 자바의 메서드와 다르게 오버로딩이 되지 않는다. 오버로딩이란 동일한 메서드명에 매개변수의 타입이나 개수만 바꿔 동일 명칭의 메서드를 여러개 정의하는것을 말한다.

 

그런데 이걸 잘 모르는 자바개발자들이 함수를 짤때 함수의 인자 개수를 근거로 오버로딩을 구현한걸 심심찮게 실무에서 접할 수 있다(나도 본적이 있다.). 아마 테스트를 안했거나 대충 한두번 돌려봤는데 에러가 없으니 성공적으로 오버로딩이 됐다고 생각하고 넘어갔으리라.

 

사실 여태 포스팅한걸 근거로 생각했을때 자바스크립트에서 함수 오버로딩이 지원되지않는다는건 쉽게 추적할 수 있다.

 

1. 함수는 변수로 취급된다.

-동일한 명칭의 변수가 여러개로 선언될 수는 없으니 당연히 오버로딩은 안된다.

 

2. 모든 변수는 전역 객체(window)의 속성으로 편입된다.

-1번이랑 비슷한 이유인데 마찬가지로 객체의 키가 겹칠순 없다.

 

그렇다면 자바스크립트로 오버로딩은 완전히 포기해야하는걸까? 비슷한 일을 하는 함수를 만들때마다 함수명칭을 만들며 명명을 어떻게해야할지 머리를 감싸고 고민해야하는걸까?

물론 그건 아니다. 자바스크립트는 매우 자유로운 언어로서 인자의 갯수나 타입을 체크하지않고 호출만 되면 일단 실행한다. 이걸 잘 활용하면 오버로딩 부럽지않게 사용할 수 있다.

자바스크립트는 함수가 몇개의 매개변수를 요구하는지 확인하는 절차를 거치지 않는다.

다만 호출하는 부분에서 보내는 인자를 하나의 객체로 관리하게 되는데 이를 변수스코프객체라 부른다.

해당 객체의 명칭은 arguments 로서 배열은 아니지만 length와 같은 속성을 지원하는 객체이다.

 


function test(){

  for(var i = 0; i < arguments.length; i++){

    console.log(arguments[i]);

  }

}

 

test(1, 2, 3, 4);


실행시켜보자. test() 함수는 매개변수를 하나도 받지않는것으로 정의했지만 실제 실행시켜보면 1, 2, 3, 4가 순차적으로 출력되는것을 볼 수 있다.

arguments에 대한 얘기를 좀 더 하고싶지만 쓰다보니 이번 포스팅이 변수스코프 객체에 대한게 아니란게 생각났다;; 해당 예제 소스를 통해 자바스크립트는 정의된것과 별도로 인자를 관리하는 arguments라는 객체를 자동으로 생성하는것을 알게되었다. 이를 이용하면 인자 개수에 따른 정의가 가능하다.

하지만 사실 arguments 객체의 요소 개수를 체크해서 진행하는 경우는 많지않고 인자가 넘어왔는지 안넘어왔는지 정도만 체크해서 진행하는 경우가 많다.

참고로 인자가 넘어오지않았을때는 해당 매개변수는 undefined 상태이다.

 

function test(num1, num2){

 console.log(num1);

 console.log(num2);

}

 

test(5);

 

그럼 이제 본 포스팅으로 들어가도록하자. 인자의 개수가 다를때 처리하는법은 알아봤다. 타입이 다를땐 어떻게 처리해야할까? 변수의 타입을 체크하고 객체의 구조를 탐색하는 과정을 리플렉션이라 한다. 즉 리플렉션을 매개변수에 사용하면 매개변수의 타입과 속성들을 알 수 있는것이다.

 

그럼 타입은 어떻게 알아낼수있을까? 일단 가장 첫번째로 기본적으로 자바스크립트가 제공하는 typeof 연산자가 있다.

 

function test(param){

  switch(typeof param){

    case "number" :

    break;

 

    case "string" :

    break;

 

    case "object" :

    break;

 

    case "boolean" :

    break;

  }

}

 

test(1);

test("hello");

test({});

test(true);

 

typeof 연산자로 타입을 체크해서 진행하는 간단한 예제이다. typeof는 자바스크립트가 제공하는 원시타입만을 체크하기때문에 자세한 타입을 추출하기에는 문제점이 있다. 즉 해당 매개변수가 객체인지 아닌지까지는 판별할 수 있지만 어떤 객체인지는 파악을 못한다는 뜻이다. 해당 문제에 대해서는 instanceof 라는 연산자가 있다.

 

function Const1(){}

 

var obj1 = new Const1;

 

console.log(obj1 instanceof Const1);

 

프로토타입체인 관계(상속관계) 까지 고려한 결과값이 나온다.

 

function Const2(){}

Const2.prototype = new Const1;

 

var obj2 = Const2;

 

console.log(obj2 instanceof Const1);

console.log(obj2 instanceof Const2);

 

이정도까지만 해도 실제 코딩할때 타입판별은 거의 이루어지는데 상속관계를 고려하지않는 타입판별이 필요한경우도있다. 즉 위 예제소스에서 Const2() 의 인스턴스는 Const1() 과 연산할때도 true가 나오는데 Const1()의 인스턴스인 경우만을 추적하고싶은경우가 있을 수 있다는 것이다. 그럴땐 toString()을 오버라이딩해서 사용한다.

 

일반적으로 가장 최상위 객체인 Object의 prototype 객체에 정의되어있는 toString()은 "[object constructor]" 를 출력한다.

 

var obj = {};

console.log(obj.toString());

 

하지만 toString()으로 타입을 판별하는거엔 몇가지 문제가있는데

 

1. 사용자정의객체는 "[object Object]" 라고 나온다.

2. 그나마 정상작동하는 내장 함수들도 toString() 이 오버라이딩 된 경우가 많아 원하는 값이 안나온다.

 

2번부터 살펴보자.

 

var arr = [1, 2, 3];

console.log(arr.toString());

 

"[object Array]" 가 나오는가? 아닐것이다. Array.prototype.toString()이 오버라이딩 되었기때문에 이때문에 내장함수들의 타입을 판별할때는 Object의 toString()을 호출하도록 코딩하여야한다.

 

console.log(Object.prototype.toString.call(arr));

 

Object.prototype에 정의되어있는 toString()의 this를 바꿔 호출하도록 한 소스이다. 2번은 이런식으로 간단하게 변경할수있다.

기본적인 내장함수인 Array, Math, Date 등은 이런식으로 사용하면 된다.

 

1번에 대해 살펴보자.

 

function Test(){}

var obj = new Test;

console.log(obj.toString());

 

위에서 말한것처럼 생성자가 아니라 Object라고 나올것이다. 이것을 해결하고자하면 2번을 해결하기위해 Object의 toString()을 호출했다면 이번엔 오버라이딩을 통해 원하는 값이 나오도록 해야한다.

 

Test.prototype.toString = function(){

  return "[object Test]";

}

 

console.log(obj.toString());

 

포스팅이 길어지고있는데 사실 오버로딩을 지원하지않는 자바스크립트에서 함수내에서 타입을 판별하는 방법일뿐 크게 어려운 부분은 없다. 이 외에도 속성을 확인하는 for in문, isPrototypeOf() 등의 함수들이 존재하니 잘 활용하면 될 것이다.

댓글
댓글쓰기 폼