· JS 에서 this = "동적으로" 결정됨
· 다른 객체지향 언어에서 this = "정적으로" 자신의 인스턴스 주소를 칭함
바인딩
= "식별자" 와 "값" 을 연결하는 과정
this 바인딩
= "this" 와 "this가 가리킬 Object" 를 연결하는 과정
ㅇ 일반함수(중첩 함수, 콜백 함수) this
👉 window(Global) Object
ㅇ 생성자(method) 함수 this
👉 생성된 인스턴스 Object
ㅇ Event this
👉 Event Object
ㅇ 화살표 함수
👉 렉시컬 this ( = 상위 스코프의 this Object )
this
가 환경에 따라 바뀌는 것 = "동적 바인딩(dynamic binding)"· Function 은 다양한 상황(환경)에서 호출 될 수 있으며, 호출 환경에 따라
this
는 "동적" 으로 세팅
·apply
,call
,bind
등으로this
가 가리키는 것을 조작할 수 있음
⚪ 함수 호출 : 함수를 직접 호출
⚪ 메소드 호출 : 객체의 메서드를 호출
⚪ 생성자 함수 호출 : 생성자 함수를 호출
⚪ 간접 호출 : apply
/ call
/ bind
등으로 함수를 간접 호출
⚪ 그 외 콜백 함수의 호출
<script>
var foo = function() {
console.dir(this);
<< 함수 호출 >>
foo(); // window
<< 메소드 호출 >>
var obj = { foo: foo };
obj.foo(); // object
<< 생성자 함수 호출 >>
var instance = new foo(); // instance
<< apply, call, bind 호출 >>
var bar = { name: 'bar' };
foo.call(bar); // bar
foo.apply(bar); // bar
foo.bind(bar)(); // bar
</script>
· callback function 은 특정 동작 이후 불려지는 함수
· 보통 다른 함수의 인자로 보내지는 함수
· 기본적으로 this 는 "전역객체 바인딩"
· 전역객체는 모든 object 의 "유일한 최상위 object"
👉 일반적으로 브라우저에서는 "window", 서버에서는 "global 객체"를 의미
· 전역객체는 전역 스코프를 갖는 전역변수를 property 로 소유
⚪ "전역함수", "내부함수", "콜백함수" 의 this
👉 "전역객체 바인딩"
⚪ "내부함수" 의 this
👉 선언 위치(일반함수, 메소드, 콜백) 와 상관없이 모두 "전역객체 바인딩"
· function 이 object 의 property value 이면 method 로서 호출
👉 Method 내부의 this 는 해당 method 를 호출한 object에 바인딩
<script>
var obj1 = {
name: "Lee",
sayName: function() {
console.log(this.name);
}
}
var obj2 = {
name: "Kim";
}
obj2.sayName = obj1.sayName;
obj1.sayName(); // Lee
obj2.sayName(); // Kim
</script>
· JS 에서 생성자는 object 를 생성하는 것
👉 기존 function 에 new
연산자를 붙여 호출
· 생성자 함수로 선언된 function 에서 생성된 object 로서 반환되기 위해서는 선언한 variable(또는 property) 에 this 를 사용해야함
👉 this 를 사용하지 않으면 function 외부에서 해당 property 접근 불가
<script>
function Person(name) {
this.name = name;
}
var me = new Person('Lee');
console.log(me); // Person {name: "Lee"}
<< new 연산자와 함께 생성자 함수를 호출하지 않으면 동작 X >>
var you = Person('Kim);
console.log(you); // undifined
</script>
apply(a, b)
👉 a = this로 사용할 객체
👉 b = arguments ( 배열 or 유사 배열 객체 )
call(a, b)
👉 a = this로 사용할 객체
👉 b = arguments list ( " , " 로 구분하여 전달 )
bind(a)()
👉 a = this로 사용할 객체
⚪ apply, call
· 본질적인 기능은 "function 호출" (1회성)
· function 호출 시, < 첫 번째 parameter(a) 로 전달한 특정 object > 를 "호출한 함수의 this" 에 바인딩
· 두 번째 parameter(b) 를 function 에 전달하는 방식만 다를 뿐, apply 와 call 의 기능은 동일
⚪ bind
· function 의 this value 영구적 변경 가능
· 본질적인 기능은 "this 로 사용할 객체"만 전달(return)
👉 function 호출 X
· < method 의 this > 와 < method 내부의 중첩 함수 or 콜백 함수의 this > 가 불일치 시 사용
<script>
var vaule = 1;
var obj = {
value = 100,
foo: function() {
console.log("foo's this: ", this); // obj
console.log("foo's this.value: ", this.value); // 100
function bar(a, b) {
console.log("bar's this: ", this); // obj
console.log("bar's this.value: ", this.value); // 100
console.log("bar's arguments: ", arguments)
}
bar.apply(obj, [1, 2]);
bar.apply(obj, 1, 2);
bar.bind(obj)(1, 2)
}
};
<< result는 모두 동일 >>
foo's this: { value: 100, foo: [Function: foo] }
foo's this.value: 100
bar's this: { value: 100, foo: [Function: foo] }
bar's this.value: 100
bar's this.arguments: [Arguments] { '0': 1, '1': 2 }
</script>
let 0 = {
name: "Daniel",
f1: () => {
console.log("[f1] this : ", this);
},
>
f2: function () {
console.log("[f2] this : ", this);
},
};
>
o.f1(); // global
o.f2(); // o
f1
은 화살표 함수로 호출 시 this
는 함수가 생성된 환경을 가리키도록 고정 ( 호출된 함수를 둘러싼 실행 컨텍스트 )
f2
는 일반 함수로 this
는 함수가 호출된 환경을 가리키며 this
는 동적으로 바뀔 수 있음 ( 새롭게 생성된 실행 컨텍스트 )
화살표 함수의 this는 정해지면 바꿀 수 없음 (call, bind, apply 적용 X)
setTimeout 등 this가 바뀌는 상황에서 유용
let 0 = {
name: "Daniel",
printName: function() {
console.log("내 이름은 ", this.name);
},
};
>
o.printName(); // 내이름은 Daniel
setTimeout(o.printName, 10); // 내 이름은 undefined
setTimeout(o.printName.bind(o), 20); // 내 이름은 Daniel
bind, call, apply
등의 함수로 this
를 조작한다.
setTimeout
은 함수 호출과는 다른 콜백 호출임.
printName
메서드는 bind
함수를 이용해 this
변수가 o
를 가리키도록 컨텍스트를 동적 바인딩함
const o = {
name: "Elice",
}
function myFunc() {
console.log(this);
}
myFunc() // window {...}
myFunc.bind(o)() // {name: 'Elice'}
myFunc.call(o, null) // {name: 'Elice'}
myFunc.apply(o, null) // {name: 'Elice'}
const name = "elice";
console.log(this); // window {...}
function myFunc() {
const name = "elice";
console.log(this);
}
myFunc(); // 일반 함수 호출시 window {...}
전역 컨텍스트에서 this
는 window
를 가리킴
일반 함수 호출에서도 this
는 window
를 가리킴
function myFunc(name) {
this.name = name;
this.getName = function () {
console.log("getName this:", this);
return this.name;
};
console.log("myFunc this:", this);
return this; // 생략 가능합니다.
}
const o = new myFunc("elice"); // myFunc this: myFunc {...}
o.getName() // myFunc this: myFunc {...}
생성자 함수 내부의 this
는 new
키워드를 통해 앞으로 만들어질 인스턴스 객체를 가리킴.
즉, 일반적으로 함수를 호출할 때는 this
가 모두 window
를 가리키지만,
함수를 객체로 생성하는 방법에만 this
가 생성하는 함수 내부를 가리킴.
const o = {
name: "elice",
myFunc: function () {
console.log(this);
},
};
o.myFunc(); // {name: 'elice', myFunc: ƒ}
const o = {
name: "elice",
myFunc: function () {
return function () { console.log(this) }
},
};
o.myFunc()(); // window {...}
객체에서의 this
는 메소드를 호출한 객체를 가리킴
하지만 객체 안 함수의 내부 함수에 this
는 동적 바인딩으로 인해 전역 객체를 가리킴
/* 생성자 함수 방식 */
function createObject() {
this.myFunc = function () {
console.log("myFunc this:", this);
return function () { console.log("myFunc return this:", this)
((수정)) return () => { console.log("myFunc return this:", this) };
};
}
const o = new createObject();
o.myFunc()();
// myFunc this: createObject {...}
// myFunc return this: window {...}
((수정 후))
// myFunc this: createObject {...}
// myFunc return this: createObject {...}
/* 객체 리터럴 방식 */
const o = {
myFunc: function () {
console.log("myFunc this:", this)
return function () { console.log("myFunc return this:", this)
((수정)) return () => { console.log("myFunc return this:", this)}
},
};
o.myFunc()();
// myFunc this: myFunc {...}
// myFunc return this: window {...}
((수정 후))
// myFunc this: myFunc {...}
// myFunc return this: myFunc {...}
생성자 함수로 만든 객체, 객체 리터럴 방식으로 만든 객체 모두 내부의 this
는 자시 자신을 가리키고 있음.
하지만 내부에서 함수를 만들고 해당 함수에서 this
를 출력 시 window
를 가리킴.
이 때, 화살표 함수를 사용하면 객체 최상위 스코프를 가리키도록 유지
/* 생성자 함수 방식 */
function createObject() {
this.myFunc = function () {
console.log("myFunc this:", this);
return function () { console.log("myFunc return this:", this) };
};
}
const o = new createObject();
o.myFunc().bind(o)(); // bind 메서드를 사용해 o객체로 고정시킵니다.
// myFunc this: createObject {...}
// myFunc return this: createObject {...}
/* 객체 리터럴 방식 */
const o = {
myFunc: function () {
console.log("myFunc this:", this)
return function () { console.log("myFunc return this:", this) }
},
};
o.myFunc().bind(o)(); // bind 메서드를 사용해 o객체로 고정 그리고 함수를 실행
// myFunc this: myFunc {...}
// myFunc return this: myFunc {...}
두 메서드의 차이는 call
메서드는 인수 목록을 받고 apply
메서드는 인수 배열을 하나 받음.
ex) call(this, var1, var2, var3, …) / apply(this, [ el, el2, el3, … ])
/* 생성자 함수 방식 */
function createObject() {
this.myFunc = function () {
console.log("myFunc this:", this);
return function () { console.log("myFunc return this:", this) };
};
}
const o = new createObject();
o.myFunc().call(o, null); // call 메서드를 사용해 o객체로 고정시킨 후 함수 실행
// myFunc this: createObject {...}
// myFunc return this: createObject {...}
o.myFunc().apply(o, null); // apply 메서드를 사용해 o객체로 고정시킨 후 함수 실행
// myFunc this: createObject {...}
// myFunc return this: createObject {...}
/* 객체 리터럴 방식 */
const o = {
myFunc: function () {
console.log("myFunc this:", this)
return function () { console.log("myFunc return this:", this) }
},
};
o.myFunc().call(o, null); // call 메서드를 사용해 o객체로 고정시킨 후 함수 실행
// myFunc this: myFunc {...}
// myFunc return this: myFunc {...}
o.myFunc().apply(o, null); // apply 메서드를 사용해 o객체로 고정시킨 후 함수 실행
// myFunc this: myFunc {...}
// myFunc return this: myFunc {...}