다른 대부분의 객체지향 언어에서 this는 클래스로 생성한 인스턴스 객체를 의미한다.
자바스크립트에서 this는 기본적으로 실행 컨텍스트가 생성될 때 함께 결정된다.
즉, this는 함수를 호출할 때 결정된다. 함수가 호출되는 방식에 따라 this가 달라진다.
누가 나를 불렀느냐
같은 함수에서this를 리턴하도록 하더라도 전역 변수에서 호출 시 window를, 특정 객체의 프로퍼티에 할당 후 obj.method(); 혹은 obj['method'](); 로 호출 시 method를 호출한다.
var obj = {
methodA : function() { console.log(this); },
inner : {
methodB : function() { console.log(this); }
}
}
obj.methodA(); // == obj
obj.inner.methodB(); // == obj.inner
this가 지정되지 않으므로 전역 객체를 가리킨다.
객체 내에서만 생성된 함수더라도, onj.inner(); 이런 식으로 객체로서 호출된 게 아닌 inner()로 호출되었다면 함수로서 호출된 것이므로 window를 리턴한다.
즉, 함수 실행 당시 주변 환경 (메서드 내부인지, 함수 내부인지 등)은 중요하지 않고, 함수 호출 구문 앞의 . 이나 [] 가 있는지가 관건이다.
// 객체 내부
var self = this;
var innerfunc = function(){
console.log(self); // 객체 리턴
};
innerfunc();
// 객체 (obj) 내의 메소드 (outer) 내에 선언
var innerFunc = () =>{
console.log(this); // 메소드를 리턴 (outer: f)
};
innerFunc();
// 콜백 함수 호출 시 대상이 될 this를 지정하지 않음
setTimeout(function() { console.log(this); }, 300);
// 콜백 함수 호출 시 대상이 될 this를 지정하지 않음
[1,2,3,4,5].foreach(function (x) {
console.log(this.x);
});
// 지정한 HTML 엘리먼트에 'click' 이벤트 발생 시마다 실행
document.body.innerHTML += '<button id="a">클릭</button>';
document.body.querySelector('#a') // 위의 element를 지정
.addEventListner('click', fuction(e){ // 클릭 시 콜백 함수
console.log(this,e); // element와 함께 this 출력
});
앞의 두 함수는 this를 지정하지 않았기 때문에 전역객체를 참조한다.
addEventListener 메서드는 콜백 함수를 호출할 때 자신의 this를 상속하도록 정의되어 있다.
콜백 함수의 제어권을 가지는 함수가 콜백 함수에서의 this를 무엇으로 할지를 결정한다.
특별히 정의되지 않은 경우 기본적으로 전역객체를 바라본다.
자바스크립트의 경우 함수 호출 시 new 명령어와 함께 호출하면 해당 함수가 생성자로서 동작한다.
어떤 함수가 생성자 함수로서 호출된 경우 내부에서의 this는 곧 새로 만들 구체적인 인스턴스 자신이 된다.
class Polygon {
constructor(name) {
this.name = name; // 여기서의 this는 각각 poly1, poly2가 된다.
}
}
const poly1 = new Polygon("One");
const poly2 = new Polygon("Two");
console.log(poly1, poly2);
// 결과
// Polygon { name : "One" }
// Polygon { name : "Two" }
앞 절의 규칙을 깨고 별도의 대상을 바인딩할 수 있다.
this를 바꿔 어떤 함수가 어느 객체 안에 있도록 할 수 있다.
https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-Call-Bind-Apply
메서드의 호출 주체인 함수를 즉시 실행하도록 하는 명령이다.
메서드에 대해서도 마찬가지로 임의의 객체를 this로 지정할 수 있다.
Function.prototype.call(thisArg[, arg1[, arg2[, ...]]])
첫 번째 인자를 this로 바인딩 / 나머지 인자는 fuction의 매개 변수로 한다.
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
Function.prototype.apply(thisArg[, argsArray])
call 메서드와 기능적으로 완전히 동일하다.
차이점은 Function의 매개변수를 배열로 받는다는 것이다.
var func = function (a,b,c){
console.log(this,a,b,c);
};
func(1,2,3); // 기본적으로 전역 객체 / Window{ ...} 1 2 3
func.apply({x: 1}, [4,5,6]} // {x:1} 4 5 6
유사 객체 배열 : 배열처럼 보이지만 key는 숫자이고, length 값을 가진 객체를 말한다.
{
0: div.text,
1: div.text,
2: div.text,
3: div.text,
length: 4,
}
Array.prototype.배열메서드.call(obj,'d');
: 배열의 프로토타입에 있는 배열 메서드를 빌려 쓰는 것이다.
: 리턴 값이 배열로 정해진 메서드가 아니라면, 얕은 복사 수행 없이 배열의 메서드를 활용할 수 있다.
A객체 내부의 생성자에서
B객체.call(this,매개변수1,매개변수2,..);
를 수행하여 다른 객체의 속성을 정의할 수 있다.
객체나 배열의 값을 하나씩 꺼내어 연산한다.
array1.push(array2); : array1 뒤에 array2 배열 자체가 들어가 2차원 배열이 된다.[1,2,3,[4,5]]
Array.prototype.push.apply(arr1, arr2); : array2의 값을 꺼내어 붙인다.[1,2,3,4,5]
Function.prototype.bind(thisArg [,arg1[, arg2, ...]]])
부분 적용 함수 : 호출하려는 메서드의 모든 인수를 넣지 않고 bind 메서드를 선언하고, 여기서 생성한 새로운 함수를 호출할 때 나머지 인수를 넣을 수 있다.상위 컨텍스트 내 / 내부 함수 외부에서 call, bind 등을 호출하면 상위 컨텍스트의 this를 전달한다.
// obj 객체 내의 outer 함수
var innerFunc = function() {
console.log(this);
};
innerFunc.call(this); // or apply - // 여기서 this는 obj
// obj 객체 내의 outer 함수
var innerFunc = function() {
console.log(this);
}.bind(this); // 여기서 this는 obj
https://ko.javascript.info/arrow-functions-basics
this를 바인딩하지 않는 함수
// 객체 (obj) 내의 메소드 (outer) 내에 선언
var innerFunc = () =>{
console.log(this); // outer
};
innerFunc();