prototype & this

이번 주차는 솔로위크이다. 스스로 복습&예습하는...!
JS에서 꽤나 중요한 prototype과 헷갈리는 this에 대해 정리한다. 정리하다가 더 도움될만한 내용은 그때 추가해야겠다!


prototype

Javascript의 모든 객체는 부모 역할을 하는 객체와 연결되어 있다. 객체 지향에서의 상속처럼 부모 객체의 프로퍼티나 메소드를 상속받아 사용한다. 이때 이 부모 객체를 prototype이라 한다.
Prototype은 생성자 함수에 의해 생성된 각각의 객체에 공유 프로퍼티를 제공하기 위해 사용한다.

// 1. 생성자 함수
function Vehicle(type, wheel) {
  this.type = type;
  this.wheel = wheel;
}
// 2. 프로토타입에 공유 프로퍼티로  메소드 추가
Vehicle.prototype.hasWheel = function() {
  console.log(`${this.type}은(는) 바퀴가 ${this.wheel} 개입니다...!`);
}

// 3. 인스턴스 생성
let BMW = new Vehicle('자동차', 4);
let MegaTruck = new Vehicle('트럭', 6);
BMW.hasWheel();          // 자동차은(는) 바퀴가 4 개입니다...!
MegaTruck.hasWheel();    // 트럭은(는) 바퀴가 6 개입니다...!

이 외에 다양한 적용방식이 있지만, 깊게 파봐야 헷갈린다. 그때그때 알아보자.


this

prototype에서도 사용했지만, this는 함수를 호출할 때 함수가 어떻게 호출되었는지에 따라 this에 바인딩할 객체가 동적으로 결정되므로, 다양하게 적용된다.

1. 함수 호출

// 1. 콘솔에서의 전역 this
this === window // true

var ap = 'apple'
console.log(ap);        // apple
console.log(window.ap); // apple
console.log(this.ap);   // apple

// 2. 중첩 함수에서의 this
function aaa() {
    console.log('aaa this: ' + this);
    function bbb() {
        console.log('bbb this: ' + this)
    }
    bbb();
}
aaa()
// aaa this: [object Window]
// bbb this: [object Window]

내부함수는 일반 함수, 메소드, 콜백함수 어디에서 선언되었든 관게없이 this는 전역객체를 바인딩한다.

2. 메소드 호출 & 생성자

메소드 내부의 this는 해당 메소드를 호출한 객체에 바인딩된다.

// 1. 객체
var obj = {
    name: 'sohee',
    sayHello: function() {
        console.log('Hi, ' + this.name);
    }
}
obj.sayHello() // Hi, sohee

// 2. 생성자
function Person(name) {
    this.name = name;
}
var person1 = new Person('sohee');
var person2 = new Person('dahyun');
person1.name // sohee
person2.name // dahyun

// 3. prototype
Person.prototype.sayHello = function() {
    console.log(`Hi, ${this.name}`);
}
person1.sayHello(); // Hi, sohee
person2.sayHello(); // Hi, dahyun

// 4. new를 붙이지 않을 경우
var person3 = Person('sunee');
person3     // undefined
window.name // sunee -> this가 전역객체에 바인딩

apply & call & bind

apply는 배열, call은 풀어서, bind는 함수를 리턴!

// EX1
var Person = function(name) {
    this.name = name;
}
var person1 = {};
var person2 = {};
Person.apply(person1, ['sohee']);
Person.call(person2, 'dahyun');
console.log(person1); // {name: "sohee"}
console.log(person2); // {name: "dahyun"}

// EX2
function Person(name, age, gender){
    this.name = name;
    this.age = age;
    this.gender = gender;
}
const person3 = {}
Person.apply(person3, ['daye', 20, 'man']); // call을 사용하면 -> Person.call(person3, 'daye', 20, 'man')
console.log(person3) // {name: "daye", age: 20, gender: "man"}

// EX3. bind
function sayHello() {
    console.log('Hi, ' + this.name);
}
const hiSohee = sayHello.bind(person1)
const hiDahyun = sayHello.bind(person2)
hiSohee()  // Hi, sohee
hiDahyun() // Hi, dahyun