본문 바로가기

Web/Javascript

[JAVASCRIPT] this

this

일반적인 객체지향언어(C#, JAVA) 에서 this 는 특별한 처리가 없는한 항상 Class 본인을 가르킨다.

그러나 Javascript 에서 this 는 상당히 독특한 모습을 보여준다.

  • this 가 가르키는 객체는 동적으로 변한다.
  • 즉 호출 시점에 따라 this 는 변한다. 
  • 기본적으로 자바스크립트에서 this 는 windowglobal 을 가르킨다. ( strict mode 에선 undefined 할당 )

객체에서 this

  • 일반 함수 호출방식의 this 는 전부 window ( 전역 객체 ) 를 가르킨다. 
  • 즉 어떤 함수라도 일반 함수로 호출되면 this 는 전역 객체
  • 메소드 형태 ( 객체가 호출하는 ) 라면 this 가 호출한 객체에 바인드 된다.
const obj = {
	name: "john",
	// 메소드 형태 선언
	foo() {
		console.log(this);  // obj

		// 함수
		function bar() {
			console.log(this);  // window
		}
		// 일반 함수 형태 호출
		bar();
	}
};

obj.foo();
일반 함수 호출 과 메소드의 차이?
일반 함수 호출은 함수형 언어에서 선언된 함수를 문자그대로 호출하는 방식 ex) add()
메소드는 객체 내부의 함수를 객채를 통하여 호출하는 경우 ex) calc.add();

 

따라서 아래와 같은 방법으로 this를 의도대로 동작하게 만든다.

일반 함수 this 일치

  • this 객체를 잃지 않고 값에 담아 내부에서 사용할 수 있도록 한다.
const obj = {
	name: "john",
	foo(){
		const _this = this;

		console.log(this, "foo"); // obj

		function bar(){
			console.log(_this, "bar");  // obj
		}
		bar();
	}
};

obj.foo();

명시적 바인드

  • apply, call, bind 를 사용해서 this를 명시적으로 바인드 할 수 있다.
const obj = {
	name: "john",
	foo(){
		setTimeout(function(){
			console.log(this.name);  // "john"
		}.bind(this), 1000);
	}
}

obj.foo();

화살표 함수

  • 화살표 함수는 내부적으로 this를 가지고 있지 않다.
const obj = {
	name: "john",
	foo(){
		setTimeout(() => {
			console.log(this.name);  // "john"
		}, 1000);
	}
}

obj.foo();

생성자 함수 this

  • 생성자 함수 ( new ) 내부의 this 는 생성자 함수가 생성할 인스턴스에 바인딩 된다.
  • new 연산자를 통해 새로운 객체를 생성하고 getName 함수는 프로토타입 체인 내부에 존재하기에
    함수 호출시 name 을 가르킨다.
  • 하지만 직접 체인 내부에서 호출시 this 를 잃어버린다. 즉 호출한 객체에 따라 this는 변경된다. *
function Person (name) {
	this.name = name;
}

Person.prototype.getName = function(){
	console.log("getName 호출!");
	return this.name;
};

const person = new Person("john");

console.log(person.getName());  // "john"
console.log(person.__proto__.getName());  // undefined

Person.prototype.name = "john2";

console.log(person.getName());  // "john"
console.log(person.__proto__.getName());  // "john2"
function Person (name) {
	this.name = name;
	// __proto__ 에서 생성되는것이 아닌 인스턴스 안에 직접 생성
	this.getName = function () {
		return this.name;
	}
}

const person = new Person("john");
console.log(person.getName());  // "john"

const windowPerson = Person("john");
console.log(windowPerson);
// new 를 사용하지 않고 일반 함수로 사용시 내부 요소들이 window 속성으로 들어가 버린다.

Class 의 this

  • class 내부에서 화살표 함수 this 는 생각과 다르게 호출객체를 가르키고 있다.
  • 이는 클래스가 내부적으로 this를 명시적 바인딩 처리 하기 때문이다.

상세한 동작 원리에 대해서는 아직 지식이 부족하다.  예외적으로 외워두자.

class Person {
    // static
    static addr = "서울";

    // Field 선언
    age = 10;

    // 인스턴스 선언
    constructor(name){
        this.name = name;
    }

    ageMethod(){
        console.log(this.age, "Method");
    }

    ageField = function(){
        console.log(this.age, "Field");
    }

    ageArrow = () => {
        console.log(this.age, "arrow");
    }
}

const person = new Person("john");

person.ageMethod();   // 10 "Method"
person.ageField();    // 10 "Field"
person.ageArrow();    // 10 "arrow"

const method = person.ageMethod;
method(); // expected error, Cannot read properties of undefined (reading 'age')
const field = person.ageField;
field(); // expected error, Cannot read properties of undefined (reading 'age')
const arrow = person.ageArrow;
arrow(); // 10 "arrow"

DOM 

  • 이벤트 리스너 내부 콜백 함수의 this 는 DOM 객체 를 가르킨다.
  <body>
    <button class="btn">버튼</button>
    <script>
      const $btn = document.querySelector(".btn");
      $btn.addEventListener("click", function (evt) {
        console.log("target", e.target); // <button class="btn">버튼</button>
        console.log("function", this);  // <button class="btn">버튼</button>
      });
      $btn.addEventListener("click", (evt) => {
        console.log("arrow", this);   // Window
      });
    </script>
  </body>
  <body>
    <button class="btn">버튼</button>
    <script>
      const $btn = document.querySelector(".btn");
      $btn.onclick = function (evt) {
        console.log(this); // <button class="btn">버튼</button>
      };
    </script>
  </body>
  <body>
    <button class="btn" onclick="onClick(this, event)">버튼</button>
    <script>
      function onClick(_this, event) {
        console.log(this); // Window
        console.log(_this); // <button class="btn" onclick="onClick(this)">버튼</button>
        console.log(event); // Event
      }
    </script>
  </body>

apply, call, bind 

  • call, apply 의 본질적인 기능은 함수를 호출하는 것 이다.
  • bind 는 함수를 호출 하지 않는다.
function thisFunc ( age ) {
	this.age = age
	return this;
}

const obj = {name: "dj"};

console.log(thisFunc(26)); // window

console.log(thisFunc.call(obj, 26));
console.log(thisFunc.apply(obj, [26]));
function thisFunc ( age ) {
	this.age = age
	return this;
}

const obj = {name: "dj"};

console.log(thisFunc(26)); // window

thisFunc.bind(obj); // 호출되지 않는다. 따라서 할당을 하거나 즉시 실행해야한다.
// thisFunc.bind(obj)();

thisFunc = thisFunc.bind(obj); // this 가 명시적으로 지정된 함수로 변경

console.log(thisFunc(27)); // obj

There might be incorrect information or outdated content.

 

 

 

'Web > Javascript' 카테고리의 다른 글

[JAVASCRIPT] for~in vs for~of  (0) 2023.08.28
[JAVASCRIPT] try-catch 에러 전파  (0) 2023.08.15
[JAVASCRIPT] isNaN 검사  (0) 2023.08.15
[JAVASCRIPT] DOM - 노드 조작  (0) 2023.08.04
[JAVASCRIPT] DOM - 노드 탐색  (0) 2023.08.04