this 바인딩 vs 렉시컬 스코프
- this : 함수를 호출할 때 함수가 어떻게 호출 되었는지에 따라 this에 바인딩할 객체가 동적으로 결정됌
- 렉시컬 스코프 : 함수를 어디에 선언하였는지에 따라 상위 스코프가 결정된다.
this 호출 방식
- 함수 호출
- 메소드 호출
- 생성자 함수 호출
- apply, call, bind 호출
function test() {
console.dir(this)
}
// 1. 함수 호출
test(); // window
// 2. 메소드 호출
var obj = {test:test};
obj.test(); // obj
// 3. 생성자 함수 호출
var instance = new test(); // instance
// 4. apply, call, bind 호출
var a = { name: 'apply, call, bind 메소드 호출'}
test.call(a); // a
test.apply(a); // a
test.bind(a)(); // a
- 4가지 방법 모두 test() 함수를 호출하였지만 this가 바인딩한 객체는 다르다
1. 함수 호출 : window (this는 전역 객체에 바인딩된다.)
2. 메서드 호출 : obj (함수가 객체의 프로퍼티 값일때는 메소드로 호출되는데 이때 this는 해당 메소드를 소유한 객체에 바인딩된다.)
3. 생성자 함수 호출 : new 연산자로 생성하였기 때문에 instance 변수에 객체(Person)를 반환한다.
4.
1. 함수 호출
1. 기본적으로 this는 전역객체에 바인딩 된다.
2. 전역객체는 전역 스코프를 갖는 전역변수를 프로퍼티로 갖는다.
3. 전역에서 선언한 함수에서 this는 전역객체의 프로퍼티로 접근 할 수 있는 전역 변수의 메소드이다.
4. 내부함수(자식함수)는 어디에서 선언되었든 상관없이 this는 전역객체를 바인딩한다.
- 그 이유는 메소드, 외부함수(부모함수)가 내부함수를 사용하여 자신의 작업을 돕게 할수 없게 만들어졌기 때문이다.
일반적인 함수에서 호출한 this
var a = '전역 변수';
function b() {
console.log('전역 함수');
}
console.log(window.a); // 전역 변수
console.log(window.b()); // 전역 함수
내부 함수와 외부 함수에서 호출한 this
- 내부 함수의 경우 this를 호출 할경우 외부 함수 객체를 바인딩 할거 같지만,
- 내부 함수와 외부 함수의 this는 모두 전역 객체를 바인딩한다.
var name = "전역 변수"
function a() {
var name = "외부 함수";
function b() {
console.log(this.name);
}
console.log(name); // 외부 함수
console.log(this.name); // 전역 변수
b(); // 전역 변수
}
a();
2. 메소드 호출
- 함수가 객체의 프로퍼티 값일때 메소드로 호출된다.
- 이때 메소드 내부의 this는 해당 메소드를 소유한 객체에 바인딩된다.
메소드에서 this를 호출할 때
var name = "전역 변수";
var obj = {
name : "obj객체 변수",
callName : function() {
console.log(this.name);
}
}
console.log(this.name) // 전역 변수
obj.callName() // obj객체 변수
메소드에서 내부 함수를 호출할 때
// parent 함수에서 this는 obj객체 변수(name)를 바인딩한다.
// inner 함수에서 this는 전역객체 변수(name)를 바인딩한다
var name = "전역 변수";
var obj = {
name : "obj객체 변수",
parent : function() {
var name = "외부함수 변수"
function inner() {
console.log(this.name)
}
console.log(this.name); // obj객체 변수
inner(); // 전역 변수
}
}
obj.parent();
3. 생성자 함수 호출
생성자 함수 : 기존 함수에 new연산자를 작성하여 호출하면 생성자 함수로 작동한다.
생성자 함수 this 바인딩 방식
1. new 연산자를 통해 작성된 생성자 함수에 빈 객체가 생성된다.
2. 생성자 함수 내에서 사용되는 this는 1번의 빈 객체를 가리킨다.
3. 생성된 빈 객체 에서는 this를 사용하여 동적으로 프로퍼티 or 메소드를 생성할 수 있다.
생성자 함수 new 연산자 붙이고 호출
- 생성자 Person함수 this는 빈객체를 가리키기 때문에 전역객체를 바인딩 못함
- new 연산자로 생성하였기 때문에 me 변수에 객체(Person)를 반환한다.
var name2 = 'ss'
function Person(name) {
console.log(this.name2); // undefined
console.log(this.name); // undefined
console.log(name); // Lee
this.name = name;
console.log(this.name) // Lee
}
var me = new Person('Lee');
console.log(me); // Person {name: "Lee"}
생성자 함수 new 연산자 붙이지 않고 호출
- 생성자 함수를 new 연산자 없이 호출할 경우 this는 전역객체를 가리켜서 전역변수가 바인딩 된다.
- new 연산자없이 생성하였기 때문에 호출할 경우 반환문이 없어 undefined를 반환한다.
var name2 = 'ss'
function Person(name) {
console.log(this.name2); // ss
console.log(this.name); // 공백(빈 객체여서 this.name을 못찾는거 같음 or undefined인데 오류인듯)
console.log(name); // Lee
this.name = name;
console.log(this.name) // Lee
}
var me = Person('Lee');
console.log(me); // undefined
4. apply/call/bind 호출