[JS_memo] 자바스크립트에서의 this

Lina Hongbi Ko·2023년 3월 22일
0

JavaScript_memo

목록 보기
5/7
post-thumbnail

자바스크립트의 "THIS"

화살표함수를 정리하고 또 여러 클론코딩을 하면서 this에 대해 강의를 듣고 또 대략은 알고 있지만 정확하게 알지 못하는 것 같아서 어느 분이 정리한것을 바탕으로 여기에 다시 정리한다.

✏️ What's this?

  • 말 그대로 this가 뭐에요?
    자바스크립트에서 this는 문맥에 따라 다양한 값을 가진다. this가 쓰이는 함수를 어떤 방식으로 실행하느냐에 따라 그 역할이 구별된다고 한다.
    this의 값들은 크게 4가지 정도로 나뉘는데 어떤 방식으로 실행하느냐에 따라 그 값이 결정된다. 이러한 특성 때문에 this가 뭔지 알기 위해서는 this가 사용된 함수가 어디서 실행됐느냐에 나뉜다.

  • this는 그럼 어떻게 실행돼요?
    JS에서 this는 정적으로 할당 되지 않고, 동적으로 할당된다.
    쉽게 말해 this가 선언되었을 때가 아닌, 호출되었을 때 결정된다는 뜻.

const person = function (name) {
    this.name = name;   // 이 때 this가 결정되는 것이 아니라
}

const person1 = new person('son');  // 이 때 결정된다.
console.log(person1.name);    

JS에서 호출에 따른 this의 해석

1. 함수 호출

일반적으로 일반 함수에서 this는 전역 객체(window)를 가르키고
모든 내부함수(함수속에 함수, 메소드 속 함수)의 this는 전역 객체(window)를 가르킨다. 콜백함수로 일반함수가 올 경우 전역객체(window)를 가르킨다.

const value = 1;

const obj = {
  value: 100,
  foo: function() {
    console.log("foo's this: ", this);  // obj
    console.log("foo's this.value: ",  this.value); // 100
    function bar() {
      console.log("bar's this: ", this); // window
      console.log("bar's this.value: ", this.value); // 1
    }
    bar();
  }
};

obj.foo();
const value = 1;

const obj = {
  value: 100,
  foo: function() {
    setTimeout(function() {
      console.log("callback's this: ", this);  // window
      console.log("callback's this.value: ", this.value); // 1
    }, 100);
  }
};

obj.foo();

2. 메소드 호출

함수가 객체의 프로퍼티 값이면, 메소드로써 호출된다. 이 때, this는 메소드를 소유한 객체가 된다. (프로토타입 객체도 메소드를 가질 수 있다. 그리고 프로토타입 객체의 this도 해당 메소드를 호출한 객체를 바인딩한다.)

const obj1 = {
  name: 'Lee',
  sayName: function() {
    console.log(this.name);
  }
}

const obj2 = {
  name: 'Kim'
}

obj2.sayName = obj1.sayName;

obj1.sayName();   // /Lee
obj2.sayName();  // kim
function Person(name) {
  this.name = name;
}

Person.prototype.getName = function() {
  return this.name;
}

const me = new Person('Cho');
console.log(me.getName());     // Cho

Person.prototype.name = 'Son';
console.log(Person.prototype.getName());    // Son

3. 생성자 함수 호출

생성자 함수란 공통 성질을 가지는 객체(인스턴스)들을 생성하는데 사용하는 함수이다. 생성자를 클래스(class), 클래스를 통해 만든 객체를 인스턴스(instance)라고 하는데, 이것은 syntax suguar로 생각할 수 있으며 JS에서의 함수는 생성자로서의 역할을 함께 한다.
new 명령어를 통해 함수를 호출하면 함수가 생성자로 동작하여 인스턴스 객체를 만드는데 이때 내부에서의 this는 새로 만들어진 인스턴스 자신이 된다.

생성자 함수를 호출하면
1. 생성자의 prototype 프로퍼티를 참조하는 __proto__ 라는 프로퍼티가 있는 객체를 생성. (이 부분 따로 정리)
2. 미리 준비된 공통 속성 및 개성을 해당 객체(this)에 부여.
new 명령어를 통해 함수를 호출하면 함수가 생성자로 동작하여 인스턴스 객체를 만들고, 이때 내부에서의 this는 새로 만들어진 인스턴스 자신이 된다.

// 생성자 함수
function Person(name) {
  this.name = name;
}

const me = new Person('Lee');
console.log(me); // {name: "Lee"}

// new 연산자와 함께 생성자 함수를 호출하지 않으면 생성자 함수로 동작하지 않습니다.
conts you = Person('Kim');
console.log(you); // undefined

📍 3-1. 생성자 함수 동작 방식

생성자 함수가 실행되기 전 빈 객체를 생성하고, 생성자 함수 내에서 사용되는 this는 이 객체를 가르킨다. 빈 객체는 생성자 함수의 prototype 프로퍼티가 가르키는 객체를 자신의 프로토타입 객체로 설정한다.
(this를 통해 this가 가르키는 객체에 프로퍼티를 생성할 수 있다)

생성자 함수의 return이 없는 경우 새롭게 바인딩 된 객체(this가 가르키는 객체)가 반환된다.

function Person(name) {
  // 생성자 함수 코드 실행 전 -------- 1번
  this.name = name;  // --------- 2번
  // 생성된 함수 반환 -------------- 3번
}

const me = new Person('Lee');
console.log(me.name);

📍 3-2 객체 리터럴 방식과 생성자 함수 방식의 차이

const object = {
	name: "park",
	age: 12,
}  // 객체 리터럴방식

const Person = function (name, age) {
	this.name = name;
	this.age = age;
}  // 생성자 함수 선언
const person1 = new Person("Lee", 13);  // 생성자 함수 방식

리터럴 방식으로 생성한 객체는 모든 객체의 조상인 Object객체와 연결되어 있고, 생성자함수로 생성한 객체는 자신을 만든 생성자 객체인 Person.prototype을 참조하고 있음을 알 수 있다.
(💡 자바스크립트 함수는 함수가 생성될때 constructor 프로퍼티 하나만 있는 객체를 생성해서 함수의 prototype과 연결한다. Person 생성자 함수를 통해서 만든 객체의 constructor 프로퍼티를 보면 Person객체가 매핑되어 있음을 알 수 있다.)

📍 3-3 생성자 함수에 new 키워드를 쓰지 않는 경우

일반함수와 생성자 함수는 차이가 없다.
대부분의 new 없이 사용하는 빌트인 생성자(Array, Regex 등)는 scope-safe Constructor Pattern을 사용합니다. 아래는 scope-safe Constructor Pattern 의 예제이다. callee는 arguments 객체의 프로퍼티로서 함수 바디 내에서 현재 실행 중인 함수를 참조할 때 사용한다. 즉, 함수 바디 내에서 현재 실행 중인 함수의 이름을 반환한다.

💡scope-safe constructor pattern : 생성자함수가 new와 함께 호출되지 않았을 때, this가 해당 함수 프로토타입에 연결되어 있지 않음을 이용한 패턴.

function A(arg) {

   // 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(100);

console.log(a.value);
console.log(b.value);

출처
https://chiefcoder.tistory.com/m/29
https://grand-unified-engine.tistory.com/14
https://velog.io/@dev-redo/Javascript-%EC%8A%A4%EC%BD%94%ED%94%84-%EC%84%B8%EC%9D%B4%ED%94%84-%EC%83%9D%EC%84%B1%EC%9E%90-%ED%8C%A8%ED%84%B4%EA%B3%BC-new.target

profile
프론트엔드개발자가 되고 싶어서 열심히 땅굴 파는 자

0개의 댓글