자바스크립트 this 를 정리합니다.
자바스크립트는 함수를 호출할때 파라미터로 전달하는 값 외에 arguments
와 this
를 추가로 전달받습니다.
1 | function square(number) { |
자바의 경우라면 this
는 객체 자신을 참조하겠지만, 자바스크립트의 경우는 조금 다릅니다.
함수 호출 방식과 this
자바스크립트의 경우 함수 호출 방식에 의해 this
에 바인딩할 객체가 동적으로 지정됩니다.
호출 방식은 아래와 같습니다.
- function 호출
- method 호출
- 생성자 함수 호출
- apply / call / bind
- ES6 arrow function
1 | var foo = function () { |
function 호출
기본적으로 this
는 전역객체(window) 에 바인딩 됩니다. 전역 함수는 물론이고 내부함수의 경우에도 this
는 외부함수가 아닌 전역객체로 에 바인딩 됩니다.
1 | function foo() { |
method 내부의 function 일 경우에도 this
는 전역객체에 바인됭 됩니다.
1 | var value = 1; |
callback function
의 경우에도 this
는 전역객체에 바인딩 됩니다.
1 | var value = 1; |
결론은,
function 은 어디에 선언되었든 관계없이 this
가 전역객체에 바인됭 됩니다.
그러나, this
가 전역객체 참조를 회피하는 방법이 있습니다.
1 | var value = 1; |
이 방법 외에도 apply
, call
, bind
메소드를 통해 참조를 변경할 수 있습니다.
1 | var value = 1; |
method 호출
함수가 객체의 프로퍼티로서 존재한다면 이는 메소드로 호출되게 됩니다. 이때 메소드 내부의 this
는 해당 메소드를 호출한 객체가 됩니다.
1 | var obj1 = { |
프로토타입 객체도 메소드를 가질 수 있습니다. 프로토타입 객체 메소드 내부에서 사용된 this
도 일반 메소드 방식과 마찬가지로 해당 메소드를 호출한 객체에 바인딩 됩니다.
1 | function Person(name) { |
생성자 함수 호출
function
에 new
연산자를 붙여 호출하면 해당 함수는 생성자 함수로 동작하게 됩니다.
1 | // 함수 |
new
연산자와 함께 생성자 함수를 호출하면 this
바인딩이 메소드나 함수 호출때와 다르게 동작합니다.
생성자 함수 동작 방식
new
연산자와 함께 생성한 함수를 호출하면 다음과 같은 순으로 동작하게 됩니다.
빈 객체 생성 및 this 바인딩
생성자 함수의 코드가 실행되기 전 빈 객체가 생성된다. 이 빈 객체가 생성자 함수가 새로 생성하는 객체이다. 이후 생성자 함수 내에서 사용되는this
는 이 빈 객체를 가리킨다. 그리고 생성된 빈 객체는 생성자 함수의prototype
프로퍼티가 가리키는 객체를 자신의 프로토타입 객체로 설정한다.this를 통한 프로퍼티 생성
생성된 빈 객체에this
를 사용하여 동적으로 프로퍼티나 메소드를 생성할 수 있다.this
는 새로 생성된 객체를 가리키므로this
를 통해 생성한 프로퍼티와 메소드는 새로 생성된 객체에 추가된다.생성된 객체 반환
반환문이 없는 경우,this
에 바인딩된 새로 생성한 객체가 반환된다. 명시적으로this
를 반환하여도 결과는 같다.
반환문이this
가 아닌 다른 객체를 명시적으로 반환하는 경우,this
가 아닌 해당 객체가 반환된다. 이때this
를 반환하지 않은 함수는 생성자 함수로서의 역할을 수행하지 못한다. 따라서 생성자 함수는 반환문을 명시적으로 사용하지 않는다.
1 | function Person(name) { |
객체 리터럴 방식과 생성자 함수 방식의 차이
1 | // 객체 리터럴 방식 |
- 리터럴 방식의 경우, 생성된 객체의 프로토타입 객체는
Object.prototype
입니다. - 생성자 함수 방식의 경우, 생성된 객체의 프로토타입 객체는
Person.prototype
입니다.
ES6 의 class
1 | class Person { |
동일한 new
연산자를 사용하였이며 class 를 사용한다고 하여 크게 다르지 않습니다.
apply / call / bind
this
에 바인딩될 객체는 함수 호출 방식에 의해 결정됩니다. 이는 자바스크립트 엔진이 암묵적으로 수행하는것이지만, 개발자가 직접 지정하는 방법을 제공하기도 합니다.
Function.prototype.apply
Function.prototype.call
이 메소드들은 모두 함수 객체의 프로토타입 객체의 메소드 입니다.
apply
1 | func.apply(thisArg, [argsArray]) |
apply 메소드를 호출하는 주체는 함수입니다.
1 | var Person = function (name) { |
빈 객체 foo
를 apply()
메소드의 첫번째 매개변수에, argument
의 배열을 두번째 매개변수에 전달하여 Person
함수를 호출했습니다.
Person
함수의 this
는 foo
객체에 바인딩 되었습니다.this.name
프로퍼티에 매개변수 name
을 대입하려 하지만, foo
객체에는 name
프로퍼티가 없으므로 name
프로퍼티가 동적으로 추가되고 값이 할당됩니다.
call
1 | Person.apply(foo, [1, 2, 3]); |
apply
와 call
메소드는 기능은 같지만 두번쨰 인자를 배열형태와 각각 넘기는것에 차이가 있을뿐입니다.
bind
ES5에 추가된 Function.prototype.bind
를 이용할 수 도 있습니다.
bind
는 함수에 인자로 전달한 this
가 바인딩되는 새로운 함수를 리턴합니다.
bind
는 apply
, call
과 달리 함수를 바로 실행하지 않기때문에 명시적으로 함수를 호출할 필요가 있습니다.
1 | function Person(name) { |
ES6 Arrow function
1 | function Foo(bars) { |
callback function
의 경우에도 this
는 전역객체에 바인딩 되는것을 위에서도 언급했습니다.
es6 에 추가된 문법인 arrow 를 사용하게 될 경우 this
는 new
키워드로 생성한 객체에 바인딩 됩니다.
1 | function Foo(bars) { |
ES6 문법이므로 babel 을 사용하여 트랜스해보면 아래와 같은 결과를 볼 수 있습니다.
https://babeljs.io/
1 | function Foo(bars) { |