본문 바로가기

Creation/Programming

[Javascript] function호출(apply, call) 및 scope에 관하여


Javascript function 및 scope에 관하여



  Javascript의 function은 특이합니다. 함수 자체가 객체가 됩니다. 이 말인 즉슨, 아래처럼 함수를 생성하면 자동으로 객체가 된다는 것인데요, 다음처럼 한번 디버깅 툴에서 입력을 해보겠습니다.


> var a = function(a) { console.log(a); }



  그리고, 아래처럼 a.length 를 치게되면 결과값은 1이 나옵니다.


> a.length


1


  입력하지도 않은 property인 length에 대한 값이 출력이 되는 것을 볼 수 있습니다. 여기서 length는 최초 함수를 만들 때의 인자의 개수 (여기서는 한개이지요)가 출력이 되도록 설정되어 있습니다.

  즉 다시 얘기하면, 함수는 자바스크립트에서 특수 객체로 취급이 되면서, 그 속성 값들은 javascript 시스템이 알아서 초기에 세팅을 한다고 보면 될 것입니다. length를 대표적으로 보았는데, 또 아래처럼 apply라는 메소드도 생성이 됩니다.


> a.apply(null, [123]);


123


  apply라는 메소드는, 위 예제의 경우 a(123)를 호출한 것과 동일한 결과를 냅니다. 함수를 호출하는 또다른 방식이라고 볼 수 있을 것입니다. apply는 두번째 인자를 array로 변환하여 넘겨주어야 하는 메소드입니다. 여러개의 인자값을 넘기게 된다면 [1, 2, 3]과 같이 넘기면 되는 것이죠.

  여기서 잠깐, 첫번째 인자값으로 넘겨진 null의 의미는 무엇일까요? 이것은 함수에서 사용할 scope를 뜻합니다. 기본적으로 C나 C++에서는 상상하기 어려운 개념인데, 이 언어들은 자동적으로 scope가 고정되어 있기 때문입니다. 자신의 함수 안은 local 변수들이, 함수 밖에는 global 변수들이 있죠. 그런데 자바스크립트에서는 이것이 유동적입니다.


  a 함수를 아래처럼 다시 선언해 보겠습니다.


> var a = function() { console.log(this); }



  이제 이 함수를 실행하면, 아래처럼 this에 해당하는 것이 window인 것을 알 수 있씁니다. Window 객체에 관련된 log가 찍혀나옵니다.


> a()


Window {stop: ƒ, open: ƒ, alert: ƒ, confirm: ƒ, prompt: ƒ, …}



  이것은 바로, 자바스크립트의 기본 scope가 WIndow로 되어있기 떄문에 나타나는 현상입니다. C로 치자면 global에 해당하는 scope가 window인 것입니다.

  그렇지만, 객체의 함수로써 동작을 하게 될 경우에는 그 객체에 해당하는 object가 this가 됩니다. 어떻게보면 최상위 객체가 window이기 때문에 위처럼 함수를 선언하게 되면 기본적으로 this가 window가 된다고 거꾸로 설명할 수도 있겠습니다.


 this를 유동적으로 변환하기 위해서는 어떻게 해야할까요? 이것에 관한 해답 중 하나가 바로 위에서 얘기하다가 만 apply함수의 첫번째 인자입니다. 위 예시에서는 null을 넘겼지만, 아래 예시처럼 scope를 마음대로 바꿀 수 있습니다.



	
var a = function() {
    this.test = 123;
};
var b = {
    test: 456
} 
	



  여기서 당연히, a()를 호출한 후 b.test를 찍어보면 변한게 없이 456이 출력될 것입니다.


> a()


undefined


> b.test


456



  그렇지만 위에서 이야기한 것처럼, a.apply(b, []) 를 활용해보면 어떨까요?


> a.apply(b, [])


undefined


> b.test


123



  scope가 b로 바뀌었기 때문에, b.test 값이 변한 것을 알 수 있습니다.



  this를 활용한 scope 변경의 예시는 참으로 많지만, 가장 쉽게 이해할 수 있는 예시를 한번 들어보았습니다. 짧은 글을 끝내기 전에, apply처럼 call도 동일한 역할을 하는 function을 생성시에 자동으로 생성되는 method라는 것을 알려드리면서 글을 마칩니다.



> a.call(b)


undefined


> b.test


123



  다만 call의 경우에는 배열로 인자를 넘겨받는 것이 아니라, 인자 a, b, c가 있으면 a.call(scope, a, b, c) 처럼 또다른 인자로 넘겨받는다는 차이점만이 존재합니다.