[JS] this

CheolHyeon Park·2021년 4월 25일
1

JavaScript

목록 보기
3/23

JS에서 this의 할당은?

JS에서 this는 정적으로 할당 되지 않고, 동적으로 할당된다.

이 말을 쉽게 해석하자면 this가 선언되었을 때가 아닌, 호출되었을 때 결정된다는 의미이다.

예)

const person = function (name) {
	this.name = name;  // 이때 this는 결정되지 않는다.
}

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

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

1. 함수 호출

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

예1)

function foo() {
  console.log("foo's this: ",  this);  // window
  function bar() {
    console.log("bar's this: ", this); // window
  }
  bar();
}
foo();

예2)

var value = 1;

var 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();

예3)

var value = 1;

var 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도 해당 메소드를 호출한 객체를 바인딩한다.

예)

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

var obj2 = {
  name: 'Kim'
}

obj2.sayName = obj1.sayName;

obj1.sayName();   // /Lee
obj2.sayName();  // kim

예2)

function Person(name) {
  this.name = name;
}

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

var me = new Person('Lee');
console.log(me.getName());

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

3. 생성자 함수 호출

JS에서 함수는 값으로 역할을 하고, new 키워드를 통해, 일반함수를 생성자 함수로 사용할 수 있다.

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

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

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

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

  1. 생성자 함수가 실행되기 전 빈 객체를 생성 → 생성자 함수 내에서 사용되는 this는 이 객체를 가르킨다. 빈 객체는 생성자 함수의 prototype 프로퍼티가 가르키는 객체를 자신의 프로토타입 객체로 설정한다.
  2. this를 통해 this가 가르키는 객체에 프로퍼티를 생성할 수 있다.
  3. 생성자 함수의 return이 없는 경우 새롭게 바인딩 된 객체(this가 가르키는 객체)가 반환한다.
  4. 생성자 함수는 명시적으로 this를 하지 않는다.
function Person(name) {
  // 생성자 함수 코드 실행 전 -------- 1번
  this.name = name;  // --------- 2번
  // 생성된 함수 반환 -------------- 3번
}

var 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);  // 생성자 함수 방식

위 객체 리터럴 방식과 생성자 함수 방식의 차이는 생성자 함수의 prototype 객체는 Object이고,

객체리터럴방식의 prototype 객체는 Person이다.

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

  • 일반함수와 생성자 함수는 차이가 없다.

대부분의 new 없이 사용하는 빌트인 생성자(Array, Regex..)는 scope-safe Constructor Pattern을 사용한다. 아래는 scope-safe Constructor Pattern 의 예제이다

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);

callee는 arguments 객체의 프로퍼티로서 함수 바디 내에서 현재 실행 중인 함수를 참조할 때 사용한다. 다시 말해, 함수 바디 내에서 현재 실행 중인 함수의 이름을 반환한다.

4. apply/call/bind 호출

apply/call/bind 이 함수들은 명시적으로 어떤 객체에 바인딩 할 수 있는 메소드들이다.

Function.prototype.apply, Function.prototype.call 이다.

func.apply(thisArgs, [argsArray]);
func.call(thisArgs, argument1, argument2...)
func.bind(thisArgs)();

출처: https://poiemaweb.com/js-this

profile
나무아래에 앉아, 코딩하는 개발자가 되고 싶은 박철현 블로그입니다.

1개의 댓글

comment-user-thumbnail
2021년 4월 25일

감사합니다

답글 달기