🔥 함수 선언이 아닌, 호출할 때 this에 바인딩할 객체가 동적으로 결정 !
실행 컨텍스트 = 문맥, 코드의 실행 환경
this 출력 : window
this의 값이 호출되는 방법에 의해 결정되기 때문에, 호출방법과 무관하게 this를 고정시키기 위해 바인드를 사용해야 한다.
일반 함수 호출 (defalut 바인딩)
객체의 메서드 호출 (암시적 바인딩)
apply | call | bind 호출 (명시적 바인딩)
생성자 함수 호출 (new 바인딩)
var foo = function () {
console.dir(this);
};
// 1. 일반 함수 호출 (defalut 바인딩)
foo(); // window
// window.foo();
// 2. 객체의 메서드 호출 (암시적 바인딩)
var obj = { foo: foo };
obj.foo(); // obj
// 3. 생성자 함수 호출 (new 바인딩)
var instance = new foo(); // instance
// 4. apply | call | bind 호출 (명시적 바인딩)
var bar = { name: 'bar' };
foo.call(bar); // bar
foo.apply(bar); // bar
foo.bind(bar)(); // bar
// in browser console
this === window // true
console.log(this) // Window {0: Window, 1: global, 2: global, …}
// in Terminal
node
this === global // true
콘솔창에 this를 찍으면 window가 나오는데, this는 javascript 실행 환경의 전역 객체라고 할 수 있다. 전역객체 (window, global)는 일반 객체처럼 제약 없이 동작하기 때문에 this를 무분별하게 사용하면 전역 상태에 영향을 줄 수 있으므로 주의해야 한다.
일반 함수 내에서 this를 호출하면 역시 this는 전역 객체(window)가 바인딩 된다. 이때 this의 객체(window)는 객체의 프로퍼티나 메서드를 참조하기 위한 변수여서, 일반 함수에서의 this는 의미가 없다.
콜백 함수가 일반 함수로 호출된다면 콜백 함수 내부의 this도 전역 객체(window)가 바인딩 된다. 즉 어떤 함수라도 일반 함수로 호출되는 경우 ! this 는 전역 객체에 바인딩 된다 !
const person ={
name : "Kim",
getName() {
return this.name;
}
};
console.log(person.getName()); // Kim
간단하게 어떤 객체를 통해 함수가 호출되면 그 객체가 바로 this의 컨텍스트 객체가 된다. person 객체를 통해 getName 함수가 호출되었기 때문에 this는 person 객체에 바인딩 되는 것 !
메서드는 프로퍼티에 바인딩 된 함수를 의미하는데, getName 프로퍼티가 가리키는 함수 객체는 person 객체에 포함된게 아니라 독 ! 립 ! 적으로 존재하는 별도의 객체다.
다른 값과 연관되어 있는 어떤 값, 객체 내 프로퍼티 키: 프로퍼티 값으로 저장됨
const anotherPerson = {
name: "Lee",
};
// getName 메서드를 anotherPerson 객체의 메서드로 할당
anotherPerson.getName = person.getName;
// getName 메서드를 호출한 객체는 anotherPerson
console.log(anotherPerson.getName()); // Lee
// getName 메서드를 일반 함수에 할당하고, 호출
const getName = person.getName();
console.log(getName()); // ''
위의 코드처럼 다른 객체(anotherPerson)의 프로퍼티에 할당하여 다른 객체의 메서드가 될 수도, 일반 변수에 할당하여 일반 함수로 호출될 수 있다.
apply, call, bind는 Function.prototype의 메서드이다. 이런 메서드는 모든 함수가 상속받아 사용할 수 있고 함수가 첫번째 인자로 넘겨주는 값이 this의 컨텍스트 객체가 된다.
call, apply는 this를 특정 객체에 바인딩해주며 함수를 호출한다.
call은 인자를 하나씩 넣어줘야하고 apply는 배열 형태로 넣어주면 된다.
function hello(message) {
console.log(`안녕 나는 ${this.name}`);
console.log(message);
}
const person1 = {
name: "철수"
};
hello("만나서 반가워"); // this: 전역객체 바인딩 => 안녕 나는 () 만나서 반가워
hello.call(person1, "만나서 반가워!"); // this: 명시적 바인딩 => 안녕 나는 철수 만나서 반가워
hello.apply(person1, ["만나서 반가워!"]); // this: 명시적 바인딩 => 안녕 나는 철수 만나서 반가워
call, apply와 비슷하지만 bind는 this에 바인딩하는 역할을 위해 만들어졌다. call, apply와 같이 함수를 호출하는 것이 아니라, this가 바인딩된 새로운 함수를 반환한다.
함수 호출이 아닌 함수 반환이기 때문에 콜백 함수를 등록할 때 사용하기도 한다.
function hello(message) {
console.log(`안녕 나는 ${this.name}`);
console.log(message);
}
const person1 = {
name: "철수"
};
const bindedHello = hello.bind(person1, "만나서 반가워");
bindedHello();
hello.bind(person1, "만나서 반가워")(); // 안녕 나는 철수 만나서 반가워
생성자 함수는 객체를 생성하는 함수이다. 생성자 함수를 통해 만들어진 객체의 this는 해당 인스턴스가 바인딩 된다.
function Person(name){
this.name = name;
}
const 철수 = new Person("철수");
console.log(철수); // Person {name: "철수"}