Study/JavaScript

[JavaScript][source analysis] 메소드 오버로딩

Bluesky_ 2009. 4. 16. 02:36
반응형

JavaScript는 메소드 오버로딩이 없다.
매개변수의 갯수나, 속성, 리턴값의 일치여부를 체크하지 않는다.
함수를 선언하고 해당 함수가 호출되기 전 동일 네임의 함수가 다시 선언되는 경우 그대로 덮어쓴다.

하지만 메소드 오버로딩의 구현은 가능하다.
이를 구현한 소스가 있다.
자바스크립트의 전도사로, jQuery의 개발자로 유명한 John Resig의 소스이다.
원글 : http://ejohn.org/blog/javascript-method-overloading
아래와 같다.
// addMethod - By John Resig (MIT Licensed)
function addMethod(object, name, fn){
	var old = object[name];
	object[name] = function(){
		if (fn.length == arguments.length) 
			return fn.apply(this, arguments);
		else 
			if (typeof old == 'function') 
				return old.apply(this, arguments);
	};
}

// Now setup the methods
function Users(){
	addMethod(this, "find", function(){
	// Find all users...
	});
	addMethod(this, "find", function(name){
		// Find a user by name
	});
	addMethod(this, "find", function(first, last){
		// Find a user by first and last name
	});
}

// Now use the methods
var users = new Users();
users.find(); // Finds all
users.find("John"); // Finds users by name
users.find("John", "Resig"); // Finds users by first and last name
users.find("John", "E", "Resig"); // Does nothing
짧고 간결하다.
하지만 짧은 코드안에 참 많은 함축적인 JavaScript의 문법들이 들어있다.
프로세스의 순서대로 나열해보자.

  1. 페이지가 호출되면 함수 선언부들이 라인별로 읽어들여진다.
  2. 27Line에서 new 전치 연산자로 Users함수가 생성자로 호출이 된다.
    1. Users 생성자는 this에 바인딩되며 생성자의 본문 내용을 메모리에 로드한다.
      1. addMethod를 만나고 addMethod의 본문이 치환되어 불려들여진다.
        1. 15Line에서 addMethod가 호출되며 인수로 3개가 넘어간다.
          1. old라는 변수에 users.find가 참조된다. (현재 users.find가 없으므로 undefined가 참조됨)
          2. users.find 메소드의 함수 선언 (실행이되는 부분이 아닌 선언부분임)
        2. 15Line에서 addMethod가 호출되며 인수로 3개가 넘어간다.
          1. old라는 변수에 users.find가 참조된다. (2-A-1-A에서 선언된 fn.length=0인 users.find가 참조됨)
          2. users.find 메소드의 함수 선언 (실행이되는 부분이 아닌 선언부분임)
        3. 21Line에서 addMethod가 호출되며 인수로 3개가 넘어간다.
          1. old라는 변수에 users.find가 참조된다. (2-A-1-B에서 선언된 fn.length=0인 users.find가 참조됨)
          2. users.find 메소드의 함수 선언 (실행이되는 부분이 아닌 선언부분임)
  3. 28Line에서 users.find() 메소드가 호출된다.
    1. Users객체에 담겨있는 addMethod의 치환 부분이 호출된다.
      1. 선언된 순서와 반대로 users.find 선언 부분이 호출된다. (fn.length=2인 user.find 선언 부분 호출)
        1. fn.length와 호출된 users.find 비교 결과 false (28Line의 호출된 users.find 메소드의 arguments=0 이므로 false)
        2. 8Line에서 이전 2-A-1-C-1에서 참조된 typeof old == 'function' true
        3. 참조되어 있던 2-A-1-B-2 메소드가 다시 users.addMethod에 선언부분으로 참조 변경됨. (2-A-1-C-2 -> 2-A-1-B-2로 참조 변경)
      2. 선언된 순서와 반대로 users.find 선언 부분이 호출된다. (fn.length=1인 user.find 선언 부분 호출)
        1. fn.length와 호출된 users.find 비교 결과 false (28Line의 호출된 users.find 메소드의 arguments=0 이므로 false)
        2. 8Line에서 이전 2-A-1-B-1에서 참조된 typeof old == 'function' true
        3. 참조되어 있던 2-A-1-A-2 메소드가 다시 users.addMethod에 선언부분으로 참조 변경됨. (2-A-1-B-2 -> 2-A-1-A-2로 참조 변경)
      3. 선언된 순서와 반대로 users.find 선언 부분이 호출된다. (fn.length=0인 user.find 선언 부분 호출)
        1. fn.length와 호출된 users.find 비교 결과 true (28Line의 호출된 users.find 메소드의 arguments=0 이므로 true)
        2. 6Line에서 이전 2-A-1-A-1에서 참조된 users.find 선언 부분이 실행된다. (16Line의 선언 부분 실행됨.)
  4. 29Line에서 users.find("John") 메소드가 호출된다.
    1. Users객체에 담겨있는 addMethod의 치환 부분이 호출된다.
      1. 선언된 순서와 반대로 users.find 선언 부분이 호출된다. (fn.length=1인 user.find 선언 부분 호출)
        1. fn.length와 호출된 users.find 비교 결과 false (28Line의 호출된 users.find 메소드의 arguments=1 이므로 false)
        2. 8Line에서 이전 2-A-1-C-1에서 참조된 typeof old == 'function' true
        3. 참조되어 있던 2-A-1-B-2 메소드가 다시 users.addMethod에 선언부분으로 참조 변경됨. (2-A-1-C-2 -> 2-A-1-B-2로 참조 변경)
      2. 선언된 순서와 반대로 users.find 선언 부분이 호출된다. (fn.length=1인 user.find 선언 부분 호출)
        1. fn.length와 호출된 users.find 비교 결과 true (28Line의 호출된 users.find 메소드의 arguments=1 이므로 true)
        2. 6Line에서 이전 2-A-1-B-1에서 참조된 users.find 선언 부분이 실행된다. (19Line의 선언 부분 실행됨.)
  5. 30Line에서 users.find("John") 메소드가 호출된다.
    1. Users객체에 담겨있는 addMethod의 치환 부분이 호출된다.
      1. 선언된 순서와 반대로 users.find 선언 부분이 호출된다. (fn.length=2인 user.find 선언 부분 호출)
        1. fn.length와 호출된 users.find 비교 결과 true (28Line의 호출된 users.find 메소드의 arguments=2 이므로 true)
        2. 6Line에서 이전 2-A-1-A-1에서 참조된 users.find 선언 부분이 실행된다. (22Line의 선언 부분 실행됨.)
  6. 31Line에서 users.find("John", "E", "Resig") 메소드가 호출된다.
    1. Users객체에 담겨있는 addMethod의 치환 부분이 호출된다.
      1. 선언된 순서와 반대로 users.find 선언 부분이 호출된다. (fn.length=2인 user.find 선언 부분 호출)
        1. fn.length와 호출된 users.find 비교 결과 false (28Line의 호출된 users.find 메소드의 arguments=3 이므로 false)
        2. 8Line에서 이전 2-A-1-C-1에서 참조된 typeof old == 'function' true
        3. 참조되어 있던 2-A-1-B-2 메소드가 다시 users.addMethod에 선언부분으로 참조 변경됨. (2-A-1-C-2 -> 2-A-1-B-2로 참조 변경)
      2. 선언된 순서와 반대로 users.find 선언 부분이 호출된다. (fn.length=1인 user.find 선언 부분 호출)
        1. fn.length와 호출된 users.find 비교 결과 false (28Line의 호출된 users.find 메소드의 arguments=3 이므로 false)
        2. 8Line에서 이전 2-A-1-B-1에서 참조된 typeof old == 'function' true
        3. 참조되어 있던 2-A-1-A-2 메소드가 다시 users.addMethod에 선언부분으로 참조 변경됨. (2-A-1-B-2 -> 2-A-1-A-2로 참조 변경)
      3. 선언된 순서와 반대로 users.find 선언 부분이 호출된다. (fn.length=0인 user.find 선언 부분 호출)
        1. fn.length와 호출된 users.find 비교 결과 false (28Line의 호출된 users.find 메소드의 arguments=3 이므로 false)
        2. 8Line에서 이전 2-A-1-A-1에서 참조된 typeof old == 'function' false
        3. 결국 아무것도 리턴되지 않고 종료

차근차근 실행된 순서들을 읽어나가다 보면 어찌하여 실행이 되었는지 알 수 있을 것이다.
사용된 JavaScript의 메소드는 다음과 같다.
function testFunction(value1, value2) {
	alert(testFunction.length);	//호출 : 매개변수의 갯수 2
	alert(arguments.length);	//호출 : 인수의 갯수 3
}
testFunction("값1", "값2", "값3");

functionObj.length는 기능함수에서 정의된 인수의 갯수이고
functionObj.arguments.length는 기능함수가 호출될 때 전달받은 인수의 갯수이다.
나머지 사항은 이전에 언급한 적이 있던 함수의 호출 을 참조하여 흐름에 대해 파악하면 될 것이다.

주의해야 하는 점은 new 전치연산자로 생성자가 Users의 addMethod를 선언한 내용을 실제 메소드 호출을 할 때 선언을 한 순서의 역순으로 실행을 한다는 점이다.
반응형