자바스크립트 입문_this (여러가지 상황에 따른)
자바스크립트 2021. 5. 4. 17:43(본 포스팅은 위키북스의 '코어자바스크립트' 책을 공부하면서 작성되었습니다_내돈내산)
<전역공간에서의 this>
- 전역공간에서 this는 전역 객체를 가리킴. 전역 객체는 자바스크립트 런타임 환경에 따라 다른 이름과 정보를 가짐.
- 브라우저 환경에서 전역객체는 window이고 Node.js환경에서는 global임.
// 브라우저 환경에서 this
console.log(this); // {alert: f(), atob: f(), blur: f() ....}
console.log(window); // {alert: f(), atob: f(), blur: f() ....}
console.log(this === window); // true
// Node.js환경에서 this
console.log(this); // { process : {title: 'node', version: ....}
console.log(global); // { process : {title: 'node', version: ....}
console.log(this === windows); // true
- 전역변수를 선언하면 자바스크립트 엔진은 이를 전역객체의 프로퍼티로 할당함
var a = 1;
console.log(a); // 1 (스코프체인에서 검색한 a)
console.log(window.a); // 1 (전역객체의 프로퍼티 a)
console.log(this.a); // 1 (this의 프로퍼티의 a)
- 삭제명령을 할때 전역객체의 프로퍼티 할당
/*--------------------------------------------------------------------------*/
var a = 1;
delete window.a; //false
console.log(a, window.a, this.a); // 1 1 1
/*--------------------------------------------------------------------------*/
var b = 2;
delete b; // false
console.log(b, window.a, this.a); //2 2 2
/*--------------------------------------------------------------------------*/
window.c = 3;
delete window.c; // true
console.log(c, window.c, this.c) // Uncaught ReferenceError: c is not defined
/*--------------------------------------------------------------------------*/
window.d = 4;
delete d; // false
console.log(d, window.d, this.d); // Uncaught ReferenceError: c is not defined
처음부터 전역객체의 프로퍼티로 할당한 경우에는 삭제가 되지만, 전역변수로 처음부터 선언한 경우에는 삭제가 되지 않음. 전역변수를 선언하면 자바스크립트 엔진이 자동으로 전역객체의 프로퍼티로 할당시킴.
<메서드로서 호출할때 그 메서드 내부에서의 this>
- 어떤 함수를 메서드로서 호출하는 경우 호출주체는 바로 함수명(프로퍼티명)앞의 객체가 됨.
var obj = {
methodA : function() {console.log(this);},
inner :{
methodB : function() {console.log(this);}
}
};
obj.methodA(); // { methodA: f, inner : {....}} (===obj)
obj['methodA'](); // { methodA: f, inner : {....}} (===obj)
obj.inner.methodB(); // { methodB: f } (===obj.inner)
obj.inner['methodB'](); // { methodB: f } (===obj.inner)
obj['inner'].methodB(); // { methodB: f } (===obj.inner)
obj['inner']['methodB'](); // { methodB: f } (===obj.inner)
<함수로서 호출할때 그 함수 내부에서의 this>
- 함수를 함수로서 호출하는 경우는 this가 지정되지 않음. 함수에서의 this는 전역 객체(window, global 등)를 가리
- 메서드 내부 함수에서의 this
obj1 = {
outer: function() { (1)
console.log(this); (3)(4)
var innerFunc = function() { (5)
console.log(this); (7)(8)(12)
}
innerFunc(); (6)
var obj2 = { (9)
innerMethod: innerFunc (11)
};
obj2.innerMethod(); (10)
}
};
obj1.outer(); (2)
- obj1 객체 생성. 객체내부에는 outer라는 프로퍼티가 있으며 이에는 익명함수가 연결됨.
- obj1.outer 호출
- obj1.outer 실행컨텍스트가 생성되며 호이스팅, 스코프체인수집, this바인딩 등이 수행됨. 이때 this에는 outer를 감싸는 객체인 obj1이 바인딩됨.
- obj1의 객체정보가 console.log명령어에 의해 출력됨.
- 호이스팅된 변수 innerFunc는 outer 스코프 내에서만 접근할 수 있는 지역변수임. 여기에 익명함수를 할당함.
- innerFunc()를 호출
- innerFunc()의 실행컨텍스트가 생성되면서 호이스팅, 스코프체인 수집, this바인딩 등이 수행됨. 이 함수를 호출할때 함수명앞에 점(.)이 없었음 즉 함수로서의 호출이 이루어졌으므로, this는 지정되지 않고 자동으로 전역객체가 바인딩 됨.
- Window 객체 정보가 출력됨.
- 호이스팅된 obj2역시 outer 내부에서만 접근가능한 지역변수임. 여기서는 객체를 재할당하는데, innerMethod라는 프로퍼티에 innerFunc()가 할당되어 있음.(정확히는 innerFunc()에 할당된 익명함수가 할당됨)
- obj2.innerMethod()를 호출함.
- obj2.innerMethod()함수의 실행컨텍스트가 생성되며 이 함수는 메서드로써 호출된 것이기 때문에 this에는 점(.) 앞의 객체인 obj2가 바인딩 되게 됨.
- innerFunc()에 할당된 익명함수에 의해 obj2의 객체 정보가 출력됨.
- 메서드의 내부함수에서의 this를 우회하는 법 : 변수를 활용함, 상위 스코프의 this를 저장해서 내부함수에서 활용할려는 수단.
var obj = {
outer: function () {
console.log(this); // - obj
var innerFunc1 = function () {
console.log(this); // Window
}
innerFunc1();
var self = this; // outer 스코프에서 self라는 변수에 this를 저장함.
var innerFunc2 = function () {
console.log(self); // obj
}
innerFunc2();
}
};
obj.outer();
- this를 바인딩하지 않는 함수(화살표함수; arrow function)
- 화살표 함수의 경우 실행컨텍스트를 생성할때 this바인딩 과정이 없음. 상위 스코프의 this를 그대로 가져다가 활용이 가능함. 우회법을 사용하지 않아도 됨.
var obj = {
outer: function () {
console.log(this); // obj
var innerFunc = () => {
console.log(this); // obj
};
innerFunc();
}
};
obj.outer();
<콜백함수 호출 시 그 함수 내부에서의 this>
- 함수의 제어권을 다른 함수에게 넘겨주는 경우 함수 A를 콜백함수라고 함.
- 콜백함수의 경우 this를 상속하는 함수도 있지만, 그렇지 않은 경우가 있어서 반드시 이렇다 할 답이 있는 것은 아님. 콜백함수의 제어권을 가지는 함수가 this를 무엇으로 할지 결정하기 때문에 특별히 정의하지 않는 경우에는 기본적으로 함수와 마찬가지로 전역객체를 바라보게 됨.
[1, 2, 3, 4, 5].forEach(function (x) {
console.log(this, x); // Window 1, Window 2, Window 3, Window 4, Window 5
});
document.body.innerHTML += '<button id="a">클릭</button>';
document.body.querySelector('#a')
.addEventListener('click', function (e) {
console.log(this, e); // button object
});
<생성자 함수 내부에서의 this>
var Cat = function (name, age) {
this.bark = '야옹';
this.name = name;
this.age = age;
};
var choco = new Cat('초코', 7);
var nabi = new Cat('나비', 5);
console.log(choco, nabi);
- 자바스크립트는 함수에 생성자로서의 역할을 함께 부여
- new 명령어와 함께 함수 호출 시 생성자로서 동작
- 함수가 생성자 함수로서 호출 된 경우 내부에서의 this는 곧 새로 만들 인스턴스 자신을 가리킴
- 인스턴스 생성 과정
- 생성자 함수 호출
- 생성자의 prototype 프로퍼티를 참조하는 __proto__ 라는 프로퍼티가 있는 객체 생성
- 미리 준비 된 공통 속성 및 개성을 해당 객체(this)에 부여
'자바스크립트' 카테고리의 다른 글
자바스크립트 입문_bind 메소드 (0) | 2021.05.05 |
---|---|
자바스크립트 입문_명시적 this 바인딩(call, apply 메소드) (0) | 2021.05.05 |
자바스크립트 입문_스코프, 스코프체인, outerEnvironmentReference (0) | 2021.05.04 |
자바스크립트 입문_함수 선언문과 함수 표현식 (0) | 2021.05.04 |
자바스크립트 입문_LexicalEnvironment, 호이스팅(hoisting) (0) | 2021.05.04 |