전역 공간에서의 this
this는 실행 컨텍스트가 생성될 때 결정(this binding) === this는 함수를 호출할 때 결정
전역 공간에서 this는 전역 객체를 가리킴 -> window(브라우저 환경)
메서드로서 호출할 때 그 메서드 내부에서의 this
함수와 메서드의 차이점 : 독립성
-함수 : 그 자체로 독립적인 기능을 수행 ex) obj1.( )
-메서드 : 자신을 호출한 대상 객체에 관한 동작을 수행 ex) obj1.method( )
var func = function (x) {
console.log(this, x);
};
// 함수로서 호출된 경우 this는 window 전역 객체를 의미한다.
func(1); // Window { ... }
var obj = {
method: func,
};
// method를 호출한 주체는 객체 obj
// this는 객체 obj를 의미함
obj.method(2); // { method: f } 2
호출의 주체를 명시하고 있을 때 this는 항상 바인딩될 수 있다.
함수로서 호출할 때 그 함수 내부에서의 this
1. 어떤 함수를 함수로서 호출할 경우, this는 지정되지 않음 (호출 주체가 없으므로)
2. 실행컨텍스트를 활성화할 당시 this가 지정되지 않은 경우, this는 전역 객체를 바라봄
3. 따라서, 함수로서 ‘독립적으로’ 호출할 때는 this는 전역 객체 (window)
메서드의 내부에서의 this
var obj = {
methodA: function () { console.log(this) },
inner: {
methodB: function() { console.log(this) },
}
};
obj.methodA(); // this === obj
obj['methodA'](); // this === obj
obj.inner.methodB(); // this === obj.inner
obj.inner['methodB'](); // this === obj.inner
obj['inner'].methodB(); // this === obj.inner
obj['inner']['methodB'](); // this === obj.inner
메서드의 내부 함수에서의 this
var obj1 = {
outer: function() {
console.log(this); // this는 obj1
var innerFunc = function() {
console.log(this);
}
// 함수로서 호출하는 것이므로 this는 전역 객체
innerFunc();
var obj2 = {
innerMethod: innerFunc
};
obj2.innerMethod();
}
};
obj1.outer();
메서드의 내부라고 해도, 함수로서 호출한다면 this는 전역 객체
this 바인딩에 관해서는 함수를 실행하는 당시의 주변 환경(메서드 내부인지, 함수 내부인지)은 중요하지 않고, 오직 해당 함수를 호출하는 구문 앞에 점 또는 대괄호 표기가 있는지가 관건임!
메서드의 내부 함수에서의 this 우회
변수 활용 (질문)
var obj1 = {
outer: function() {
console.log(this);
var innerFunc1 = function() {
console.log(this);
}
// 함수로서 호출하는 것이므로 this는 전역 객체
innerFunc1();
// self라는 변수에 this를 할당한 후 self를 출력한다
// 여기서 self는 obj1.outer()에서 출력된 this의 값 obj1이 된다
var self = this;
var innerFunc2 = function() {
console.log(self);
};
// this(self)는 obj1이 된다
innerFunc2();
}
};
obj1.outer();
화살표 함수
var obj = {
outer: function() {
console.log(this);
var innerFunc = () => {
console.log(this);
};
// 함수로서 호출하는 것이지만 this는 obj가 됨
innerFunc();
}
}
obj.outer();
화살표 함수는 실행 컨텍스트를 생성할 때 this 바인딩 과정 자체가 없음. 따라서 this는 이전의 값(상위값)이 유지됨
콜백 함수 호출 시 그 함수 내부에서의 this
setTimeout(function () { console.log(this) }, 300);
[1, 2, 3, 4, 5].forEach(function(x) {
console.log(this, x);
});
document.body.innerHTML += '<button id="a">클릭</button>';
document.body.querySelector('#a').addEventListener('click', function(e) {
console.log(this, e);
});
1. setTimeout 함수, forEach 메서드는 콜백 함수를 호출할 때 대상이 될 this를 지정하 지 않으므로 this는 곧 window객체
2. addEventListner 메서드는 콜백 함수 호출 시 자신의 this를 상속하므로 this는 addEventListner의 앞부분 (button 태그)
명시적 this 바인딩
자동으로 부여되는 상황별 this의 규칙을 깨고 this에 별도의 값을 저장하는 방법
call 메서드
호출 주체인 함수를 즉시 실행하는 명령어
var obj = {
a: 1,
method: function (x, y) {
this 5
console.log(this.a, x, y);
}
};
obj.method(2, 3); // 1 2 3
obj.method.call({ a: 4 }, 5, 6); // 4 5 6
apply 메서드
call 메서드와 완전 동일하지만 두 번째 인자가 배열이라는 부분만 다름
var func = function (a, b, c) {
console.log(this, a, b, c);
};
func.apply({ x: 1 }, [4, 5, 6]); // { x: 1 } 4 5 6
var obj = {
a: 1,
method: function (x, y) {
console.log(this.a, x, y);
}
};
obj.method.apply({ a: 4 }, [5, 6]); // 4 5 6
call / apply 메서드 활용
유사배열객체 (array-like-object)
반드시 length가 필요하며 index 번호가 0번부터 시작해서 1씩 증가한다.
slice() 함수
slice() 함수는 배열로부터 특정 범위를 복사한 값들을 담고 있는 새로운 배열을 만드는 데 사용한다. 첫 번째 인자로 시작 인덱스(index), 두 번째 인자로 종료 인덱스를 받으며, 시작 인덱스부터 종료 인덱스까지 값을 복사하여 반환한다.
// 객체에는 배열 메서드를 직접 적용할 수 없다.
// 유사배열객체에는 call 또는 apply 메서드를 이용해 배열 메서드를 차용할 수 있다.
// 유사배열객체
var obj = {
0: 'a',
1: 'b',
2: 'c',
length: 3
};
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' ]