this, call, apply

and bind

mock char

  • this
  • call
  • apply
  • bind

this

what is this

MDN - this

JavaScript에서 함수의 this 키워드는 다른 언어와 조금 다르게 동작합니다.

또한 엄격 모드와 비엄격 모드에서도 일부 차이가 있습니다. 대부분의 경우 this의 값은 함수를 호출한 방법이 결정합니다. 실행하는 중 할당으로 설정할 수 없고 함수를 호출할 때 마다 다를 수 있습니다.

ECMAScript 5는 함수를 어떻게 호출했는지 상관하지 않고 this 값을 설정할 수 있는 bind 메서드를 도입했고, ECMAScript 2015는 스스로의 this 바인딩을 제공하지 않는 화살표 함수를 추가했습니다.

this의 4가지 규칙

1. 기본 바인딩

2. 암시적 바인딩

3. 명시적 바인딩(bind)

4. new 바인딩

기본 바인딩

function whereIsJaemin() {
    console.log(this.jaemin)
}

var jaemin = '저는 여기 있어요.';

whereIsJaemin();

// 결과 : 저는 여기 있어요.

strict 모드에서의 기본 바인딩

function whereIsJaemin() {
	'use strict';
    console.log(this.jaemin)
}

var jaemin = '전역에 있어요';

whereIsJaemin()

// 타입 에러 : this는 undefined

암시적 바인딩

function whereIsJaemin() {
    console.log(this.jaemin);
}

var person = {
    jaemin: 'person 객체 안에 있어요',
    whereIsJaemin : whereIsJaemin
}

var person2 = {
    jaemin: 'person2 객체 안에 있어요',
    person: person
}

person.whereIsJaemin();

person2.person.whereIsJaemin();

// person 객체 안에 있어요
// person 객체 안에 있어요

문제

function whereIsJaemin() {
    console.log(this.jaemin);
}

var inner = {
    jaemin: '객체 안에 있어요',
    whereIsJaemin : whereIsJaemin
}

var jaemin = '밖에 있어요';

var jaeminFind = inner.whereIsJaemin;

jaeminFind()
var somone = {
    name : 'jaemin',
    whoAmI : function() {
        console.log(this);
    }
}

someone.whoAmI();

var anotherWhoAmI = someone.whoAmI;
anotherWhoAmI();

// {name: "jaemin", whoAmI: f}
// window {~~}

call and apply

명시적 바인딩 call

function greeting() {
    console.log(this.name + '님 안녕하세요.')
}

var person = {
    name : 'jaemin'
}

greeting.call(person);

// jaemin님 안녕하세요.
var user = {
    name: 'jaemin',
	friend: {
		name: 'kiwoong'
	}
}

var profile = function(age, height, weight) {
    console.log(this)
    return `
        name   : ${this.name}  
        age    : ${age}
        height : ${height}cm
        weight : ${weight}kg`;
}

console.log(profile.call(user, 32, 180, 100));
console.log(profile.call(user.friend, 32, 180, 90));

Call

var user = {
    name: 'jaemin',
	friend: {
		name: 'kiwoong'
	}
}

var profile = function(age, height, weight) {
    console.log(this)
    return `
        name   : ${this.name}  
        age    : ${age}
        height : ${height}cm
        weight : ${weight}kg`;
}

console.log(profile.apply(user, [32, 180, 100]));
console.log(profile.apply(user.friend, [32, 180, 90]));

Apply

bind

function greeting() {
    console.log(this.name + '님 안녕하세요.')
}

var person = {
    name : 'jaemin'
}

var hello = greeting.bind(person);

hello();
// jaemin님 안녕하세요.
if (!Function.prototype.bind) {
  Function.prototype.bind = function(oThis) {
    if (typeof this !== 'function') {
      // ECMAScript 5 내부 IsCallable 함수와
      // 가능한 가장 가까운 것
      throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
    }
 
    var aArgs   = Array.prototype.slice.call(arguments, 1),
        fToBind = this,
        fNOP    = function() {},
        fBound  = function() {
          return fToBind.apply(this instanceof fNOP
                 ? this
                 : oThis,
                 aArgs.concat(Array.prototype.slice.call(arguments)));
        };
 
    if (this.prototype) {
      // Function.prototype은 prototype 속성이 없음
      fNOP.prototype = this.prototype;
    }
    fBound.prototype = new fNOP();
 
    return fBound;
  };
}

new 바인딩

function person(name) {
  this.name = name
}

Person.prototype.hello() {
  console.log(this.name)
}

var greeting = new person('jaemin');
greeting.hello(); 

// "jaemin"

arrow function this

function greeting() {
    return function() {
        console.log(this.name + '님 안녕하세요.');
    }
}

var person = {
    name: 'jaemin'
}

greeting.call(person)
Made with Slides.com