자바스크립트에서 함수가 호출될 때 매개변수로 전달되는 인자외에 arguments객체와 this를 자동으로 전달받게 된다.
2021/01/28 - [개발/Javascript] - arguments, rest parameter
javascript에서 this는 함수가 소속된 객체를 가리키는데 Java와는 달리 this에 바인딩되는 객체는 해당 함수 호출 방식에 따라 달라진다.
*바인딩(Binding)이란 함수 호출과 실제 함수를 연결하는 방법이다. 즉 함수를 호출하는 부분에 함수가 위치한 메모리 번지를 연결시켜 주는 것이다.
함수의 호출 방식
-
함수 호출
-
메서드 호출
-
생성자 함수 호출
-
apply, call 호출
함수 호출
원시 타입을 제외한 자바스크립트의 모든 값들은 객체이다. 그중 최상위에 위치한 객체를 전역 객체(global object)라고 한다.
브라우저에서의 전역 객체 : window
node.js(서버)에서의 전역 객체 : global
function func() {
if(this === global){
console.log("func this = global");
}
}
func()
//func this = global
function func() {
if(this === global){
console.log("func this = global");
}
function innerFunc() { //내부함수
if(this === global){
console.log("innerFunc this = global");
}
}
innerFunc();
}
func()
//func this = global
//innerFunc this = global
함수 호출 참고
-
global scope에서 선언한 전역 변수와 함수는 전역 객체의 property와 method가 된다.
-
기본적으로 this는 전역 객체에 바인딩된다.
-
내부 함수의 this는 일반 함수, 메서드, 콜백 함수 어디에서 선언되었는지에 관계없이 전역 객체에 바인딩된다.
메서드 호출
함수가 객체의 메서드라면 this는 해당 메서드를 호출한 객체에 바인딩된다.
//전역객체에서 메소드 호출
function func() {
if(this === global){
console.log("func this = global");
}
}
global.func()
//func this = global
//funcObj객체에서 메소드 호출
let funcObj = {
"func" : function () {
if(this === global){
console.log("func this = global");
}
else if (this === funcObj) {
console.log("func this = funcObj")
}
else{
console.log("don`t know`")
}
}
}
funcObj.func();
//func this = funcObj
//funcObj객체에서 메소드 호출을 실행하였으나 내부함수(innerFunc)의 this는 전역객체 global에 바인딩된다.
let funcObj = {
"func" : function () {
if(this === global){
console.log("func this = global");
}
else if (this === funcObj) {
console.log("func this = funcObj")
}
else{
console.log("don`t know`")
}
function innerFunc() { //내부함수
if(this === global){
console.log("innerFunc this = global");
}
else if (this === funcObj) {
console.log("innerFunc this = funcObj")
}
else{
console.log("don`t know`")
}
}
innerFunc();
}
}
funcObj.func();
//func this = funcObj
//innerFunc this = global
메서드 호출에서도 내부 함수는 전역 객체에 바인딩된다.
생성자 함수 호출
생성자 함수 호출 시 작동 순서
- 빈 객체 생성 및 this가 빈 객체에 바인딩된다.
- this를 통한 property와 method 생성
- 생성된 객체 반환
function FuncObj(name) {
//this를 통한 맴버 생성
this.name = name;
this.func = function() {
console.log(`func this = ${this.name}`);
}
//생성된 함수 반환
}
let func1 = new FuncObj("func1");
let func2 = new FuncObj("func2");
console.log(func1.name)
func1.func()
console.log(func2.name)
func2.func()
//func1
//func this = func1
//func2
//func this = func2
생성자 함수 호출 참고
-
new 키워드를 통해 생성자 함수를 호출하게 되면 this는 생성된 객체를 가리키게 된다.
-
일반 함수와 생성자 함수에 특별한 차이는 없으며, 함수에 new 연산사를 붙여 호출하면 해당 함수는 생성자 함수로 동작한다.
-
일반 함수를 호출하면 this는 전역 객체에 바인딩되지만, new 연산자와 함께 생성자 함수를 호출하면 생성자 함수 내부의 this는 생성자 함수에 의해 암묵적으로 생성된 빈 객체를 가리킨다.
생성자 함수에 new 연산자를 붙이지 않고 호출할 경우, 함수 내부의 this는 전역 객체에 바인딩된다.
또한 new와 함께 생성자 함수를 호출하는 경우에 암묵적으로 반환하던 this도 반환하지 않으며, 반환문이 없으므로 undefined를 반환하게 된다.
이러한 위험을 회피하기 위해 사용되는 Scope-Safe Constructor 패턴
// Scope-Safe Constructor Pattern
function A(arg) {
// 생성자 함수가 new 연산자와 함께 호출되면 함수의 선두에서 빈객체를 생성하고 this에 바인딩한다.
/*
this가 호출된 함수(arguments.callee, 본 예제의 경우 A)의 인스턴스가 아니면 new 연산자를 사용하지 않은 것이므로 이 경우 new와 함께 생성자 함수를 호출하여 인스턴스를 반환한다.
arguments.callee는 호출된 함수의 이름을 나타낸다. 이 예제의 경우 A로 표기하여도 문제없이 동작하지만 특정함수의 이름과 의존성을 없애기 위해서 arguments.callee를 사용하는 것이 좋다.
*/
if (!(this instanceof arguments.callee)) {
return new arguments.callee(arg);
}
// 프로퍼티 생성과 값의 할당
this.value = arg ? arg : 0;
}
var a = new A(100);
var b = A(10);
console.log(a.value);
console.log(b.value);
//100
//10
apply, call 호출
함수 호출 패턴에 의해 결정되는 암묵적 this 바인딩 이외에 this를 특정 객체에 명시적으로 바인딩하는 방법
//생성자 함수 FuncObj
function FuncObj(name) {
this.name = name;
this.func = function(){
console.log(`func this = ${this.name}`);
}
}
let func1 = {};
//두가지 방법 모두 같은 결과를 출력
FuncObj.apply(func1, ["JJJ"]);
FuncObj.call(func1, "JJJ");
console.log(func1);
func1.func()
//{ name: 'JJJ', func: [Function] }
//func this = JJJ
apply, call 참고
-
apply와 call 모두 함수 객체에 속해있는 method이다.
-
this를 특정 객체에 바인딩해준다.
-
본질적인 기능은 함수 호출이다.
참고
opentutorials.org/course/743/6571
velog.io/@litien/Javascript-This-Binding
'개발 > Javascript' 카테고리의 다른 글
데이터 타입, 표준 내장 객체(Standard Built-in Object), 타입 변환 (0) | 2021.02.03 |
---|---|
prototype(프로토타입) (0) | 2021.02.02 |
객체(object) (0) | 2021.01.28 |
arguments, rest parameter (0) | 2021.01.28 |
closure(클로저) (0) | 2021.01.27 |