this

GY·2021년 8월 29일
0

[JS] 개념 정리

목록 보기
23/32
post-thumbnail

함수 실행되는 방식

this는 함수가 실행되는 순간에 값이 결정되기 때문에, 어떻게 실행되었는지를 통해 값을 알아내야 한다.

Regular Function Call 일반 함수 선언문


  • this값은 Global Object 전역객체로, 브라우저에서는 window 객체이다.
  • strict mode에서는 undefined 이다.
"use strict";

this를 포함한 함수가 실행되는 방식을 확인해야 한다.

var age = 30;

const person = {
  age: 20,
  printAge: function () {
    bar();
//bar()함수는 일반 함수로 실행되었다. 따라서 this는 전역객체이다.
  },
};

function bar() {
  console.log(this.age);

//이 this의 값이 무엇인지를 알기 위해서는 
//this를 가진 bar()가 어디에서 어떤 방식으로 실행되었는지 봐야한다.

}

person.printAge(); //30
//dot notation같아보이지만, 이 함수의 실행방식은 중요하지 않다.
//this를 가진 bar함수를 실행시키는 역할일 뿐이다.

Dot Notation (Object Method Call)


  • this는 Dot앞에 있는 객체를 가리킨다.
  • 예) a.foo() →ken객체를 가리킨다.
function makePerson(name, age) {
//전역객체로 this값이 설정된다. = age 30
  return {
    name,
    age,
    verifyAge: () => {
      return this.age > 21;
//화살표 함수는 this를 가지고 있지 않다. 따라서 상위스코프로 올라가 값을 찾는다.
    },
  };
}

const a = makePerson("ken", 30);
//함수 실행 시점 (일반함수 방식으로 실행)
if (a.verifyAge()) {
  alert("Yes, Beer!");
} else {
  alert("No, Beer!");
}
var age = 100;

function verifyAge() {
  return this.age > 21;
//이 this값을 알기 위해선 this를 포함한 veryfyAGe() 가 실행되는 장소와 방식을 확인해보자.
}

const a = {
  age: 20,
  verifyAge: verifyAge,
};

const sevenEleven = {
  sellBeer: function (customer) {
    if (!verifyAge()) {
// verifyAge()는 일반함수 방식으로 실행되었다.
//따라서 this는 전역객체>> age = 100
      return "No Beer";
    }

    return "Beer";
  },
};

sevenEleven.sellBeer(a); //Beer
function makePerson(name, age) {
//4. makePerson의 this값을 확인하기 위해서는 이 함수가 실행되는 곳을 찾는다.
  return {
    name,
    age,
    verifyAge: () => {
//3. 원래대로라면 30이지만...화살표함수는 this가 없다. 따라서 상위 스코프를 탐색한다.
      return this.age > 21;
//1. this값을 알기 위해서는 verifyAge()가 실행된 곳을 찾는다.
    },
  };
}

const a = makePerson("a", 30);
//5. 일반함수 방식으로 실행되었다. this는 전역객체이다.
//6. 전역 객체에는 age가 없으므로 undefined > undefined>21 = false

if (a.verifyAge()) {
//2. verifyAge는 여기서 실행된다. Dot Notation방식이다.
  alert("Yes, Beer!");
} else {
  alert("No, Beer!");
}
//No, Beer!

Explicit Binding : Call, Apply, Bind

Function.prototype.call

.call 메소드는 첫 번째 인자로 받은 값을 this로 설정하여 함수를 실행한다.

두 번째 인자를 시작으로 나머지 인자들은 해당 함수의 인자로 전달됩니다.

function Animal (name) {
	this.name = name;
}

function Human ( name, language) {
	Animal.call(this, name) ;
	this.language = language;
}

//Animal에서 name값을 받아온다.
function logAge () {
	console.log(this.age);
}

const person = {
	age : 20
{;

logAge.call(person);
//20
//logAge함수를 실행하는데,this는 person으로 정한다는 의미

logAge()
//undefined
function foo(a,b,c){
	console.log(this.age);
	console.log(a+b+c);
}

var a = {
	age:35
};

foo.call(a,1,2,3,4,5)
//첫번째 인자는 this값
//이후 인자는 매개변수로 쓰인다.

//35
//6

null???

Untitled

//안 종신

Untitled

var title = "wow";

const person = {
	title : "oh",
	getAge : function bar () {
		console.log(this.title);
	}
};

const people = {
	person
};

people[0].getAge.apply(null);

Apply

call과 비슷하지만, this값을 결정할 인자 이후 매개변수로 쓰일 인자를 배열의 형태로 입력한다는 차이가 있다.

foo.apply(a, [1,2,3]);
foo.call(a,1,2,3);

Vehicle.apply(this, arguments);는 Vehicle의 this들을 그대로 받으란 뜻

.call과 .apply는

  • 첫 번째 인자를 this값으로 설정한다.
  • 메소드가 사용된 함수를 실행시킨다.

bind

  • 복제해 새로운 함수를 반환한다. 반환된 함수를 실행해야 원본 함수가 실행된다.

bind는 call과 apply와 달리 함수를 실행시키지 않는다.
새로운 함수를 반환하고 변수에 담는다.
이 반환된 함수를 직접 실행해야만 메소드가 사용된 원본 함수가 실행된다.

function foo() {
	console.log(this.age);
}

var a = {age: 33};

var bar = foo.bind(a);

//bind는 foo를 복제하여 ken을 this값으로 하는 bar라는 새로운 함수를 반환한다.

bar(); //33

//사실 일반함수 형식으로 실행되었지만, bind가 있을 경우에는 우선순위가 바뀌어
//bind의 방식대로 this를 실행한다.

new keyword

new라는 함수명을 써서 함수를 실행시키는 방법

생성자 함수는 보통 객체를 만들 때 많이 쓴다.

키워드 : 자바스크립트에 내장된 명령어

function foo(){
	console.log(this);
//this = {}  와 같은 느낌으로 생각하면 된다.
}

new foo(30); //foo{}

//new를 사용하면 this에 새로운 새 객체가 생성된다.
function foo(){
	this.age = 30;
	console.log(this);
}

new foo();

//foo {age: 30}
//new 키워드를 사용해 생성된 빈 객체에 30 키 밸류가 들어갔다.

🚩Quiz

const something = {
  age: 10,
  speak: function () {
    console.log(this.age);
  }
};

const butler = {
  age: 20,
  serve: function (cb) {
    cb();
//일반함수 형태로 this값을 포함한 speak function 호출
  }
};

butler.serve(something.speak);

//전역에 age라는 변수가 없다.
//serve에서 일반함수로 호출되어 this가 전역객체를 가리키고, 
//전역에 age라는 변수가 존재 하지 않아 undefined 반환

function Programmer() {
  this.isSmart = false;

  this.upgrade = function (version) {
    this.isSmart = !!version;
    work();
  };

  return this;
}

function work() {
  if (this.isSmart) {
    window.alert("I can do my work! I am smart!");
  }
}
//일반함수 호출이라 전역객체인데, 전역객체에 issmart변수가 없음 >undefined 반환

const programmer = new Programmer();

programmer.upgrade(1);

Other Quiz

Resource

  • newCall()이 일반함수 형태로 호출하여, 전역변수에 this가 없으므로 undefined가 반환된다.
const call = {
  caller: "mom", 
  says: function() {
    console.log(`Hey, ${this.caller} just called.`);
  }
};

let newCall = call.says;

newCall();
//Hey, Undefined just called.
function logThis(){
  console.log(this);
}

class myClass {
  logThat(){
    logThis.call(this)
  }
}

const myClassInstance = new myClass()
myClassInstance.logThat()
//myClass{}

Result - The object created by myClass.Explanation:

  • Is logThis an arrow function? - No.
  • Was logThis called with new? - No.
  • Was logThis called with call / apply / bind? - Yes, whatever passed in as first argument. OK, but we are passing this! what is this refers to inside the logThat execution context? Lets check:
    • Is logThat an arrow function? - No.
    • Was logThat called with new? - No.
    • Was logThat called with call / apply / bind? - No.
    • Was logThat called as an object method? - Yes, this is the object left to the dot - The auto created object inside myClass in this case.

11. eventHandler()

Answer #11

function logThis() {
  console.log(this);
}

const btn = document.getElementById('btn');
btn.addEventListener('click', logThis);
//btn

Result - The btn element.ExplanationThis is a tricky question because we never talked about event handlers attached to DOM elements. You can look at event handlers that are attached to DOM elements as if the function is a method inside the element's object, In our case the btn object. We can look at it as if we did btn.click() or even btn.logThis(). Note that this is not exactly whats going on under the hood, but this visualization of the invocation of the handler can help us with the formation of our "mental model" regarding the setting of this.You can read more about it on the MDN

Now lets walk through the flow:

  • Is logThis an arrow function? - No.
  • Was logThis called with new? - No.
  • Was logThis called with call / apply / bind? - No.
  • Was logThis called as an object method? - Yes (sort of), in our case btn is left to the dot.

Delayed Greeting

const object = {
  message: 'Hello, World!',

  logMessage() {
    console.log(this.message); // What is logged?
  }
};
setTimeout(object.logMessage, 1000);

//undefined

//setTimeout() 함수가 콜백함수를 호출할 때는 일반함수 형태로 호출한다. 따라서 전역변수를 찾고, 전역스코프에 message 변수는 없으므로 undefined를 반환한다. 

7 Interview Questions on "this" keyword in JavaScript. Can You Answer Them?

After a delay of 1 second, undefined is logged to console. Try the demo.

While setTimeout() function uses the object.logMessage as a callback, still, it invokes object.logMessage as a regular function, rather than a method.

And during a regular function invocation this equals the global object, which is window in the case of the browser environment.

That’s why console.log(this.message) inside logMessage method logs window.message, which is undefined.

Side challenge: how can you fix this code so that 'Hello, World!' is logged to console? Write your solution in a comment below!

Question 5: Greeting and farewell

What logs to console the following code snippet:

const object = {
  who: 'World',

  greet() {
    return `Hello, ${this.who}!`;
  },

  farewell: () => {
    return `Goodbye, ${this.who}!`;
  }
};

console.log(object.greet());    // What is logged?
console.log(object.farewell()); // What is logged?

//HEllo, World!
//Goodbye, undefined!

//arrow function이기 때문에 상위 전역 스코프에서 this값을 찾고, 없기 때문에 undefined가 된다
profile
Why?에서 시작해 How를 찾는 과정을 좋아합니다. 그 고민과 성장의 과정을 꾸준히 기록하고자 합니다.

0개의 댓글