이번 글에서는 자바스크립트의 self 에 대해 알아보려고 한다.
this는 많이 접해보았을텐데 self 는 다소 생소할 수 있다. 이번 글을 통해 self가 무엇인지 한 번 알아보도록 하자.
1. self란 무엇인가?
w3c의 문서를 확인해보면, self는 읽기 전용 속성이며 WindowProxy로서의 window 자신을 반환한다고 한다.
꽤 난해한 설명인데 WindowProxy는 또 무엇인지 궁금해 할 수 있다. WindowProxy는 브라우징 컨텍스트와 관련되어있는 주제이므로추후 다른 글에서 자세히 알아보도록 하고, 지금은 단순히 전역 객체인 window 객체 자체를 반환한다고 이해하면 된다.
self는 결국 전역 객체인 window를 반환하는 속성이다.
self가 this와 같은 키워드라고 오해할 수 있는데, self는 엄연한 속성의 이름일 뿐이다.
위 스크린샷 이후 내용은 아래와 같다.
By using self, you can refer to the global scope in a way that will work not only in a window context (self will resolve to window.self) but also in a worker context (self will then resolve to WorkerGlobalScope.self)
간략히 요약하자면, 윈도우 컨텍스트가 아닌 컨텍스트(웹 워커)에서도 self 를 통해 전역 스코프 객체에 접근할 수 있다고 한다.
이 잠시 뒤 알아보도록 하고, 먼저 window 컨텍스트에서의 self를 알아보자.
아래와 같은 코드를 실행시켜보면 true 값이 출력되는 것을 확인할 수 있다.
self는 전역에 정의된 속성이기 때문에 window.self 와 동일하다.
전역 객체인 window를 생략하더라도 self가 컨텍스트의 탐색 가능한 스코프 내에 존재한다면 문제 없이 접근 가능하다.(이러한 특성을 스코프 체이닝이라고 하며 스코프에 대한 자세한 내용은 아래 글을 확인하길 바란다)
쉽게 이해하자면 아래 코드를 통해 알 수 있다.
전역에 선언하는 변수는 window.변수이름 = 값; 과 동일하다.
전역에 선언한 변수 myVariable에 접근하기 위해선 window.myVariable로 접근하는 방법도 있지만, 스코프 체이닝을 통해 myVariable 단독으로 표기하여 접근할 수도 있다.
위 코드를 절차적으로 정리해보자면 아래와 같다.
- myFunc 함수 호출
- myVariable 변수에 접근 시도
- myFunc 컨텍스트의 스코프에 myVariable이 존재하는지 확인
- 존재하지 않기 때문에 상위 스코프(전역 스코프)에서 myVariable이 존재하는지 확인
- 전역에 존재하기 때문에 전역의 myVariable 값을 참조하여 콘솔에 로그 남기기
만약 전역에도 존재하지 않아 더이상 탐색이 불가할 경우에는 ReferenceError가 발생한다.
이처럼 self의 경우에도 window.self 대신 self와 같이 단독으로 사용할 수 있다.
2. 다른 컨텍스트에서의 self
앞서 살펴본 코드는 전역 객체가 window인 환경에서의 self를 알아보았다.
self는 window 컨텍스트가 아닌 웹 워커(Web Worker) 컨텍스트에서 주로 활용되는데, 웹 워커는 전용 워커, 공유 워커, 서비스 워커 등의 다양한 종류의 워커가 존재한다.
웹 워커는 일반적인 페이지 코드와 같이 동작하지 않고 브라우저의 별도 스레드에서 작동하는데, 자바스크립트는 싱글 스레드 기반으로 동작하기 때문에 브라우저의 다른 스레드에서 동작하는 워커를 활용하여 많은 비용이 필요한 작업을 효과적으로 처리하거나 담당하는 특수한 기능을 수행할 수 있다.
웹 워커에 대한 자세한 내용은 아래 링크에서 확인할 수 있다.
https://developer.mozilla.org/ko/docs/Web/API/Web_Workers_API
self는 워커의 컨텍스트에서도 동일하게 사용할 수 있습니다.
아래 코드는 임시로 간단한 워커 스크립트를 만들고, 새로운 워커를 생성한 코드이다.
각각의 컨텍스트에서 self를 로그에 기록하도록 코드를 작성했는데 어떤 결과가 나오는지 확인해보자.
하나는 window, 다른 하나는 DedicatedWorkerGlobalScope로 기록된 모습을 확인할 수 있다.
문서의 내용대로 window 컨텍스트에서는 window 객체가, 웹 워커의 컨텍스트에서는 DedicatedWorkerGlobalScope를 참조하는 모습을 확인할 수 있다.
문서 상에는 WorkerGlobalScope라고 정의되어있었으나 앞에 Dedicated라는 수식어가 붙은 전역 객체가 콘솔 기록에 남아있는데, 이는 워커에 따라 전역 객체가 조금씩 다르기 때문이다.
위와 같은 전용 워커는 DedicatedWorkerGlobalScope, 공유 워커는 SharedWorkerGlobalScope, 서비스 워커는 ServiceWorkerGlobalScope 이며, 모두 WorkerGlobalScope의 범주에 속한다.
앞서 self는 워커 컨텍스트에서 자주 사용한다고 언급했는데, 아래와 같은 상황이라고 가정해보자.
웹 워커 내에서 이벤트를 등록할 때 전역 객체의 addEventListener를 사용하고 있다.
전역 객체에 포함되어있는 메소드이기 때문에 전역 객체를 생략하고 바로 사용해도 동작하며 기능상으로 동일하다.
다만 그냥 눈으로 봤을 때 어디에, 어떤 대상에 이벤트를 등록하는지 모호해 보일 수 있는데, self 키워드를 사용하여 명시적으로 해당 웹 워커에 이벤트를 등록하겠다는 표현방식으로써 자주 사용한다.
3. 다른 상황에서의 self
개발되는 코드를 보면 종종 아래 코드의 1번과 같은 self 가 목격되기도 한다.
이는 this를 임시로 저장하기 위한 이름이 self인 단순 변수일 뿐 앞서 설명했던 self와는 아무런 관계가 없다.
단지 함수의 this 바인딩 문제를 피하기 위한 일종의 트릭 중 하나이며, 변수이 이름일 뿐이다.
이벤트 핸들러 함수에서 외부의 this를 참조하고 싶다면 2번 코드와 같이 this를 직접 바인딩하여 사용하는 등의 방법도 있지만 여러가지 방법이 존재하니 상황에 맞게 구현하면 된다고 본다.
다시 본론으로 돌아와서, 오늘 알아본 self 는 아래와 같이 한 줄로 정리할 수 있다.
self는 스크립트가 실행되는 컨텍스트의 전역 객체를 반환하는 속성이다.
window에선 window, 워커에선 WorkerGlobalScope.
결국 코드가 실행되는 위치에서의 전역 객체를 참조하기 위한 속성이라고 정리할 수 있다.
오탈자, 내용 오류 등 발견되는 문제는 댓글로 알려주길 바라며, 다음에 더 다양한 내용으로 찾아올 수 있도록 하겠다.
참고 자료
https://docs.w3cub.com/dom/window/self/
https://docs.w3cub.com/dom/workerglobalscope/self/
https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Inner_and_outer_windows
https://html.spec.whatwg.org/multipage/window-object.html#windowproxy