JAVASCRIPT의 this

잔잔바리한접시·2022년 2월 1일
1

javascript

목록 보기
1/10
post-thumbnail

이론이 부족해..

졸업작품을 기한 내에 끝내기 위해 이론 공부를 스킵하고 구현에만 애쓰던 도중 다른 개발자들의 코드에 유독 많이 등장하는 this라는 키워드 때문에 코드 해석이 불가능해서 this의 개념과 사용법을 공부하고 넘어가기로 마음먹었따..

this가 뭐야...

자바스크립트에는 this라는 키워드가 존재함.
this는 문맥에 따라 다양한 값을 가지는데, this가 쓰이는 함수를 어떤 방식으로 실행하느냐에 따라서 그 역할이 구별됨.

1. 일밤 함수 실행 방식(Regular Fucntion Call)

첫 번째로, 일반 함수 실행 방식으로 함수를 실행했을 때, this의 값은 Global Object를 가리킴. 즉, 브라우저 상에서의 window 객체를 말함. 일반 함수 실행 방식이란 아래 예저 코드처럼 우리가 함수를 선언한 후 실행할 때 흔히 사용하는 방식을 말함

function foo () {
	console.log(this);
}
foo();

위 코드에서 foo라는 함수를 선언, 실행함. 이 때, foo 함수 안에 있는 this는 글로벌 객체로 브라우저 상에서 window 객체를 가리킴.

var name = "정훈"

function foo () {
	console.log(this.name); //정훈
}
foo();

위 코드에서 우리는 전역 변수로 name이라는 변수를 만들고 "정훈"이라는 값을 할당함. 이 변수는 전역 변수이기 때문에 전역 객체인 window 객체에 속성으로 추가됨. 즉 우리가 var name = "정훈"이라는 코드를 쓰면 window 객체에 name이라는 key와 "정훈"이라는 vaule가 추가됨.

var age = 100;

function foo() {
	var age = 99;
    bar(age);
}

function bar() {
	console.log(this.age); // 100
}

foo();

위 코드에서 foo 함수 안에서 bar함수가 실행되고 있음. bar 함수는 this.age를 콘솔에 출력하고 있음. 이 때 bar 함수는 foo 함수 내부에서 일반 함수 실행 방식으로 실행되고 있음. 그러므로 우리가 bar함수에 매개변수로 어떤 값을 넘기든 간에 bar 함수 내부의 this.age는 window.age를 가리키고, 이는 전역 변수로 선언된 age 변수의 값을 말함. 그러므로 위 코드가 실행되면 99가 아닌 100이 출력됨.

strict mode에서 일반 함수 실행 방식(Regular Function Call in Strict Mode)

strict mode란 단어 그대로 엄격한 형식을 뜻함. 즉, strict mode에서 실행되는 모든 코드들에 좀 더 엄격한 규칙들이 적용됨. strict mode에서는 비엄격 모드(sloppy mode)에서 자주 일어나는 다양한 실수를 방지하여 각종 에러들을 감소시킴.

strict mode를 사용하려면 스크립트 코드 맨 상단에 'use strict'; 구문을 추가하면 됨.

'use strict';

var name = "정훈"

function foo() {
	console.log(this.name); // error
}

foo();

보통 일반 함수 실행 방식에서 this는 window 객체를 가리키지만 strict mode에서는 this가 무조건 undefined임. 그렇기 때문에 위 코드에서 this.name을 출력하면 foo 함수가 아무리 일반 함수 실행 방식으로 실행되었다고 하더라도 strict mode이기 때문에 this는 undefined가 된다. 또한 undefined에는 어떠한 속성도 없으므로 this.name을 실행할 수 없어 에러가 출력됨. 보통 코드를 작성할 때 this가 실수로 window 객체로 인식되어서 예상치 못한 에러가 발생하기도 하는데, strict mode는 그러한 버그의 발생을 방지함.

도트 표기법(Dot Notation)

Dot Notation은 우리가 Object를 만들고 그 Object의 key와 value를 부여한 후 도트(.)로 값에 접근하는 방식을 말함.

var age = 100;

var ken = {
	age: 26,
    foo: function() {
    	console.log(this.age); // 26
    }
}

ken.foo();

ken이라는 변수에 Object를 만듦. 그리고 foo라는 key에 this.age를 출력하도록 함수를 만들었음. 그 후 ken.foo();를 통해 함수를 실행하고 있는데 이렇게 도트(.)를 사용해 객체 속성의 값에 접근하는 방ㅅ기을 Dot Notation이라고 함.

Dot Notation으로 함수가 실행되면, this는 도트(.) 앞에 써있는 객체 자체를 가리킴. 즉, 위 코드에서 this.age의 this는 ken을 가리킴. 그러므로 this.age는 ken.age와 같기 때문에 26이 출력됨.

function foo() {
	console.log(this.age);
}

var age = 100;
var ken = {
	 age : 26,
     foo : foo,
}

var wan = {
	age : 32,
    foo : foo,
}

ken.foo(); // 26
wan.foo(); // 32

var fn = ken.foo(); // 100
fn();

우선 전역 변수 age를 선언하여 100이라는 값을 할당 함. 그 후 ken이라는 객체를 선언, age와 foo라는 key를 부여하였음. 여기서 foo의 value는 함수 foo의 이름임. wan 객체도 마찬가지.

이 상황에서 우리가 ken.foo();로 함수를 실행하면 이 때의 foo 함수는 Dot Notation 방식으로 실행되었기 때문에, this는 ken 객체 자체를 가리키게 되고 26이라는 값이 출력 됨. wan.foo();도 마찬가지.

아래 fn이라는 변수에 우리는 ken.foo();라는 값을 입력하고 fn();을 실행하였음. 이는 Dot Notation이 아닌 일반 함수 실행 방식으로 실행된 것임. 그러므로 이때 this는 Global Object를 가리키게 되고 전역 변수 age의 값이 100이 출력 됨.

명백한 바인딩(Explict Binding)

명백한 바인딩, 즉 this의 역할을 작성자가 직접 명확하게 지정한다는 뜻임. 이는 function.prototype.call, function.prototype.bind, function.prototype.apply와 같은 메서드를 사용하면 됨.

var age = "100";

function foo() {
	console.log(this.age);
}

var ken = {
	age : 26,
    log : foo,
}

foo.call(ken, 1, 2, 3);

위 코드에서 foo 함수에 call 메서드를 사용하여 실행하였는데 인자로 각각 ken, 1, 2, 3을 주었음. 이 인자들 중 가장 첫 번째로 쓴 ken이 바로 this의 값으로 지정됨. 1, 2, 3은 this의 값과는 상관없이 순서대로 foo 함수가 됨. 그러므로 위 코드에서 this.age는 ken.age가 되어 26이 출력됨.

var age = 100;

function foo() {
	console.log(this.age);
}

var ken = {
	age : 26,
    log : foo,
}

foo.apply(ken,[1, 2, 3, 4]);

위 코드에서 apply 또한 call과 같은 역할을 함. apply는 this의 값을 지정해주는 인자 외에도 배열을 인자로 넣을 수 있는데, 이 배열의 값이 순차적으로 foo 함수의 인자가 됨.

new 키워드를 사용한 함수 실행

함수를 그냥 foo();와 같은 형태로 실행할 수 있지만 new 키워드를 사용해서 생성자 함수로 만들어 사용할 수 있음. 이 경우에 this는 빈 객체가 됨.

function Person() {
	console.log(this);
}

new Person();

위 코드에서 Person이라는 함수를 선언하였고 new Person(); 즉 new 키워드를 사용하여 Person 함수를 생성자 함수로 사용함. 이 때 this는 빈 객체를 가리키며 위의 생성자 함수는 this라는 빈 객체를 return함. (이 때 return문이 없더라도 생성자 함수의 특징으로 빈 객체를 return함)

function Person() {
 this.name = "정훈"
 console.log(this);
}

var ken = new Person();
console.log(ken);

위 코드에서 Person이라는 함수가 있고, this.name = "정훈" 이라는 구문이 있음. 만약 이 코드가 일반 함수 실행 방식으로 실행되었다면, this는 window를 가리키게 될 것이고 window 객체에 name이란 속성과 "ken"이란 값이 추가되었을 것임. 또한 위 코드는 return이 없기 때문에 어떠한 값도 리턴하지 않으므로 ken이란 변수에 어떤 것도 할당되지 않아 콘솔에 undefined가 출력될 것임.

그러나 위 함수는 new Person(); 즉, 생성자 함수로 실행됨. 그러므로 this는 빈 객체를 생성하여 name이란 속성과 "정훈"이란 값을 할당할 것이고 return문이 없음에도 불구하고 객체가 리턴됨. 그러므로 ken이란 변수에는 {name : "정훈"}이라는 객체가 할당되어 콘솔에 객체가 리턴됨.

function foo() {
	var age = 100;
    return 3;
}

var a = new foo();
console.log(a);

생성자 함수는 그 특징으로 인해 return문이 있음에도 불구하고 return문을 무시, this 객체를 return하는 특징이 있음. 즉, 위의 코드에서 일반 상식으로는 3이 리턴되어야 하지만 생성자 함수로 사용되었기 때문에 { age : 100 }이 리턴됨.

function foo() {
	this.age = 100;
    return { myAge : 26 };
}

var a = new foo();
console.log(a);

그러나 생성자 함수에서 리턴되는 대상이 객체라면 this 객체 대신에 해당 객체가 리턴됨. 즉 위에서는 { age : 100 }이 아니라 { myAge : 26 }이 리턴됨.

0개의 댓글