this; //window
function foo(){
console.log(this);
}
foo();
// this가 출력되는데
// this는 window 객체이므로 window가 출력된다.
var obj={
fn: function(){ console.log(this); }
}
obj.fn();
// 객체의 키값을 실행하면 this가 출력되는데
// this는 obj를 가리키므로 obj인 {fn: ƒ}가 출력된다.
function Car() {
// this는 클래스Car의 instance
this.name = name;
this.color = color;
}
//construction
var benz = new Car('benz');
var avante = new Car('avante');
.call
.apply
호출 : call, apply의 첫번째 인자로 명시된 객체.call
은 바로 실행.bind
는 this를 가지고 있는 채로 함수를 리턴한다.function foo(){
console.log(this);
}
foo.call({a:1}); // this는 첫번째 argument
var obj = {
foo: function(){
console.log(this);
}
}
var obj2 = {
foo: obj.foo
}
obj.foo.call(obj2); // obj2
(실행 컨텍스트 콜스택)
this
키워드는 execution context의 구성요소 중 하나이다.
함수가 실행될 때 this가 결정된다.(Call Time에 결정된다.)
= 코드만 봐서는 this가 무엇을 가리키고 있는지 알기 어렵다.
function getSalaryFromServer (callback){
setTimeout(function (){
callback(100000);
}, 1000);
} // 1초 후에 callback을 실행, 100000을 넘긴다.
function member (){
return {
first: 'Adela',
last: 'K',
age: 40,
printDetail: function (){
getSalaryFromServer(function (salary){
console.log(`Name: ${this.first} ${this.last}`);
// 여기서 this는?
console.log(`Salary: ${salary}`);
});
}
}
}
var adela = member();
adela; // {first: "Adela", last: "K", age: 40, printDetail: ƒ}
adela.printDetail();
/* 1초 후에 console에 아래처럼 찍힌다.
Name: undefined undefined
Salary: 100000
*/
console.log(`Name: ${this.first} ${this.last}`);
// 여기서 가리키는 this는????????
callback(10000)
로 함수를 실행시켰기 때문에 this가 상위 객체를 따라가지않고 window
가 된다.아래처럼 getSalaryFromServer로 부터 받아온게 아니라면 this
는 상위 객체가 될 것이다.
function memberSync (){
return {
first: 'Adela',
last: 'K',
age: 40,
printDetail: function (){
// getSalaryFromServer(function (salary){
console.log(`Name: ${this.first} ${this.last}`);
// 여기서 this는???????
// console.log(`Salary: ${salary}`);
// });
}
}
}
let me = memberSync();
me.printDetail(); // Name: Adela K
콜백 안의 this를 상위객체로 해서 콘솔에 Adela K를 찍게하고 싶다면?
(= 맨 위의 member 함수처럼 비동기적으로 받아오면서 this가 window가 아닌 상위객체를 가리키게 하고싶다면?)
bind
를 써볼 수 있다.
bind는 this를 갖고있는 채로 함수를 리턴한다.
function getSalaryFromServer (callback){
setTimeout(function (){
callback(100000);
}, 1000);
} // 1초 후에 callback을 실행, 100000을 넘긴다.
function member (){
return {
first: 'Adela',
last: 'K',
age: 40,
printDetail: function (){
getSalaryFromServer(function (salary){
console.log(`Name: ${this.first} ${this.last}`);
// 콜백 안의 this를 상위객체로 해서 콘솔에 Adela K를 찍게하고 싶다면 ?
console.log(`Salary: ${salary}`);
}.bind(this));
// 1. printDetail에 있는 this라고 명시해주면 this는 객체가 된다.
}
}
}
var adela = member();
adela;
// {first: "Adela", last: "K", age: 40, printDetail: ƒ}
adela.printDetail();
/* 1초 후에 console에 아래처럼 찍힌다.
Name: Adela K
VM500:11 Salary: 100000
*/
화살표 함수는 문제를 좀 더 간단하게 만들어 준다.
function member (){
return {
first: 'Adela',
last: 'K',
age: 40,
printDetail: function (){
getSalaryFromServer((salary) => {
console.log(`Name: ${this.first} ${this.last}`);
// 여기서 this는??????
console.log(`Salary: ${salary}`);
});
}
}
}
let adela = member();
adela.printDetail();
/* 1초 후에 console에 아래처럼 찍힌다.
Name: Adela K
VM500:11 Salary: 100000
*/
화살표 함수의 특징은 this가 화살표 함수 안의 새로운 실행컨텍스트를 만들지 않고, this는 그대로 lexical한 구조(member함수의 리턴된 객체)를 따라가게 된다.
???어렵다ㅠ
binding이 꼬일 것 같다면 화살표 함수를 쓰면 더 간단해진다.
실제로 화살표 함수를 ES5로 변환해주는 툴을 쓰면 solution1처럼 출력된다.
ES5의 this는 어디에서보다 어떻게호출되는 지가 더 중요했다.
ES6의 arrow function을 사용한 함수는 어디에서 호출되는지만 고려하면 된다.
arrow function만의 execution context를 만들지 않는다.
function foo(){
let that = this;
let f =() => {
console.log(that == this)
}
f();
}
foo(); // true
따라서 arguments라는 키워드도 없고,
(대신 Rest Parameter를 쓰면 된다.)
function foo(){
let that = this;
let args = arguments;
let f =() => {
console.log(that === this) // true
console.log(args === arguments) // true
}
f.call({a:1});
// call은 무시된다. f()와 똑같이 취급
}
foo();
.call, .apply로 화살표함수를 실행하게되면 this바인딩은 무시된다. 의미가 없다.
function이라고 정의된 {}안의 범위까지만 execution context를 만들고
화살표함수는 실행컨텍스트를 만들지 않는다.
let obj= {
i: 10,
b: () => console.log(this.i, this), // ? undef, window
c: function() {
console.log(this.i, this) // ? 10, obj
}
}
obj.b
의 화살표 함수는 실행 컨텍스트를 만들지 않는다.
=> undefined와 window
obj.b
의 lexical한 this는 window이다. global의 this는 window이기 때문.
obj.c
의 function은 실행될 때 실행 컨텍스트를 만든다.
따라서 method invocation형식에 따라 this는 상위객체 obj가 된다.
let foo = () => {};
let foo = new Foo(); // Foo in not a constructor
화살표 함수 foo는 construction mode를 아예 할 수 없다.
따라서 new키워드가 필요할 때 화살표함수를 쓰면 안된다. function을 쓰거나 class 키워드를 써야한다.
lexical한 this를 가지고 싶을 때 = 독자적인 execution context를 만들고싶지 않을 때
=> 화살표 함수를 사용하는 것이 훨씬 더 직관적이다.