학습내용
this
실행 컨텍스트에서 현재 객체를 참조하는 키워드. 이때 객체는 함수 호출 방법에 따라 달라진다.
window
(브라우저), global
(node 환경)등의 전역 객체를 가리킨다. 예를 들어 브라우저 환경의 전역 공간에서 this === window
는 true
를 반환한다. 따라서 전역 변수를 선언할 때는 var
, let
, const
키워드를 사용하지 않아도 된다. 변수가 전역 객체의 프로퍼티로 선언되기 때문이다.
단, this
를 사용하는 함수를 일반 함수로 호출하면 this
는 전역 객체를 참조한다. 화살표 함수를 사용하면 이를 예방할 수 있다. 화살표 함수에서는 this
가 전역 객체를 참조하지 않고 함수가 선언된 곳의 this
를 참조한다.
전역 공간(Global Scope)
가장 바깥쪽에 존재하는 영역으로 프로그램이 시작될 때 생성되며, 프로그램이 종료될 때까지 유지된다. 이 영역에 선언된 변수를 전역 변수(Global Variable), 함수를 전역 함수(Global Functino)라고 한다. 전역 변수와 전역 함수는 모든 코드에서 접근 가능하기 때문에 전역 공간은 코드의 모듈성을 해치고, 의존성이 높아진다는 문제가 있다. 그러므로 전역 변수와 전역 함수를 최소화 하고 지역 공간을 활용하는 편이 좋다.
지역 공간(Local Scope)
함수 내에서 선언한 변수와 매개변수들이 포함된 공간으로 함수가 실행될 때 생성되며, 함수가 실행을 완료하면 소멸된다.function addOne(num) { let count = 0; return num + 1; }
위 코드에서
count
는addOne
함수의 지역 공간에서 선언되었으므로,addOne
이 호출될 때마다count
가 새롭게 생성된다. 즉, 변수는 함수 내부에서만 접근 가능하며 함수 외부에서는 존재하지 않는다.이처럼 함수 내에서 필요한 데이터를 안전하게 보관하고, 전역 공간을 불필요하게 오염시키지 않아 안정적인 코드 작성이 가능하다.
this
가 지정되지 않았으므로 전역 객체 window
를 가리킨다. 단, strict mode에서는 this
가 undefined
를 가리킨다.
var func = function (x) {
console.log(this, x);
};
func(1);
this
= window
주체가 되는 객체를 가리킨다.
var obj = {
method: func, // 위 함수의 func
};
obj.method(2) // = obj['method'](2)
method
는 obj
에 의해 호출되었으므로 this
= obj
함수와 메서드의 차이
- 함수
단독 호출 가능 ex)getAge();
- 메서드
호출 주체 필요 ex)person.getAge();
일반 함수와 마찬가지로 전역 객체를 가리킨다. this binding을 결정짓는 요소는 해당 함수를 호출하는 구문 앞에 .
과 []
의 여부다. 메서드 내부인지, 함수 내부인지 등의 주변 환경은 영향을 미치지 않는다.
var obj1 = {
outer: function() {
console.log(this); // obj1
var innerFunc = function() {
console.log(this); // window
}
innerFunc();
var obj2 = {
innerMethod: innerFunc
};
obj2.innerMethod();
}
};
obj1.outer();
첫 번째 this
obj1
이 outer
를 호출하고 있으므로 this
= obj1
두 번째 this
outer
메서드 내부에 있지만 innerFunc()
함수를 독립적으로 호출하고 있으므로 this
= window
this
우회하기변수 활용
var = obj1 = {
outer: function() {
console.log(this); // obj1
var innerFunc1 = function() {
console.log(this); // window
}
innerfunc1();
var self = this; // obj1
var innerFunc2 = function() {
console.log(self);
};
innerFunc2()'
}
};
obj1.outer();
원래대로라면 innerFunc2()
호출 시 this
가 window
를 반환해야하지만, outer
에서 받아온 this
값을 self
라는 변수로 할당했기 때문에 obj1
을 반환한다.
화살표 함수
var obj = {
outer: function() {
console.log(this); // obj
var innerFunc = () => {
console.log(this); // obj
};
innerFunc();
}
};
obj.outer();
화살표 함수는 this binding 과정을 생략하므롤 상위 메서드의 this
값이 유지된다.
setTimeout
setTimeout(function() { console.log(this) }, 300);
setTimeout
함수는 this
를 지정하지 않기 때문에 window
반환 (정확히는 console.log(this)
함수를 호출하는 과정에서 this
가 유실되기 때문)
forEach
[1, 2, 3, 4, 5].forEach(function(x) {
console.log(this, x);
});
forEach
메서드는 this
를 명시할 수도 있지만 아무런 명시가 없을 시에는 window
를 반환한다.
addEventListner
document.body.innerHTML += '<button id="a">클릭</button>'
document.body.querySelector('#a').addEventListener('click', function(e) {
console.log(this, e);
});
addEventListner
메서드는 스스로의 this
를 상속하기 때문에 <button id="a">클릭</button>
반환
인스턴스(생성자 함수로 만든 객체)를 가리킨다.
var Cat = function(name, age) {
this.bark = "이얏호응";
this.name = name;
this.age = age;
};
var yattong = new Cat('야통', 4) // this = yattong
var mu = new Cat('무', 3), // this = mu
매개변수를 할당해서 this
값을 지정한다.
this
값 지정var func = function(a, b, c) {
console.log(this, a, b, c);
};
func(1, 2, 3)
➡️ window{...} 1 2 3
func.call({x:1}, 4, 5, 6)
➡️ {x:1} 4 5 6
this
값 변경var obj = {
a: 1,
method: function(x, y) {
console.log(this.a, x, y);
};
obj.method(2, 3)
➡️ 1 2 3
this
는 obj
를 가리키므로 this.a
는 a:1
이다.
obj.method.call({a:4}, 5, 6)
➡️ 4 5 6
객체 안에 지정한 a
의 값도 call
메서드로 변경 가능
call
메서드와 동일하나 두 번째 인자를 ,
가 아닌 [배열]
로 구분
func.call({x:1}, 4, 5, 6)
= func.aplly({x:1}, [4, 5, 6])
유사 배열 객체(array-like-object)에 배열 메서드 적용
유사 배열
배열은 아니지만 배열처럼 동작하는 객체var obj = { 0: 'a', 1: 'b', 2: 'c', length: 3 };
배열과 마찬가지로
length
를 갖고 있으며index
가 0부터 시작해서 1씩 증가한다.
Array.prototype.push.call(obj, 'd');
console.log(obj);
{ 0: 'a', 1: 'b', 2: 'c', 3: 'd', length: 4 };
var arr = Array.prototype.slice.call(obj);
console.log(arr);
['a', 'b', 'c', 'd']
slice()
배열로부터 특정 범위의 값을 복사 후 해당 값들을 모아 새로운 배열로 생성하는 함수. 첫 번째 인자로 시작index
, 두 번째 인자로 종료index
를 받으며 시작부터 종료까지의 값을 복사 후 반환한다.
arguments
에 배열 메서드 적용
function a() {
var argv = Array.prototype.slice.call(arguments);
argv.forEach(function(arg) {
console.log(arg);
});
}
a(5,1,2);
5
1
2
a
함수가 호출될 때 a
의 인자를 call
메서드를 통해 넘겨받음
NodeList에 배열 메서드 적용
<div>첫 번째 div</div>
<div>두 번째 div</div>
<div>세 번째 div</div>
var nodeList = document.querySelectorAll('div');
var nodeArr = Array.prototype.slice.call(nodeList);
nodeArr.forEach(function(node) {
console.log(node);
});
<div>첫 번째 div</div>
<div>두 번째 div</div>
<div>세 번째 div</div>