this의 4가지 동작 방식

uoayop·2022년 1월 5일
1

WEB

목록 보기
8/8

this

자바에도 인스턴스화 된 객체인 자기자신을 접근할 수 있는 this가 있다.

JS에도 this라는 키워드가 있다.

문맥에 따라 this는 다른 값을 가진다.

this가 쓰이는 함수를 어떤 방식으로 실행하느냐에 따라 그 역할이 구별됨

1. 기본 바인딩

  • this는 Global Object 를 가리킴
    • 브라우저상에서는 window 객체
var name = 'Julia';

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

foo();

strict mode일 때

  • strict mode : 실행되는 모든 코드들에 대해 좀 더 엄격한 규칙들을 적용시킴
    비엄격 모드에서 자주 일어나는 다양한 실수들을 방지해서 에러를 감소

  • use strict

  • this는 무조건 undefined


2. 암시적 바인딩

  • 도트 표기법 : 객체를 만들고, 그 객체의 key와 value를 부여한 후 도트로 값에 접근

  • 어떤 객체를 통해 함수가 호출되면, 그 객체가 바로 this의 context 객체가 됨

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

var age = 100;
var ken = {
    age: 36,
	foo: foo
}
var wan = {
    age: 32,
	foo: foo
}

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

var fn = ken.foo; 
// 일반 실행 함수 방식
// 전역 객체에 프로퍼티를 등록한 것과 같음
// ken.foo == window.foo 
fn(); // 100

3. 명백한 바인딩

  • this의 역할을 직접 명확하게 지정시켜줌

    • function.prototype.call
    • function.prototype.bind
    • function.prototype.apply
    • call, bind, apply 모두 첫번째 인자로 넘겨주는 것이 this의 contxt 객체가 됨!
      null이나 undefined를 넣으면 자동으로 global object를 가리킴
  1. call : 첫번째 인자로 쓴 값이 this로 지정됨
    두번째 인자부터 함수에 사용할 인자들을 쉼표로 구분지어 넣어줌

  2. apply : 첫번째 인자로 쓴 값이 this로 지정됨,
    두번째 인자에 함수에 사용할 인자를 배열로 담아 넣어줌

    var age = 100;
    
    function foo() {
    	console.log(this.age);	// 35
    }
    
    var ken = {
    	age: 35,
    	log: foo
    }
    
    foo.apply(ken, [1, 2, 3, 4, 5]);
    // foo의 this를 ken으로 설정
  3. bind : call과 apply는 함수의 실행값을 반환하는 반면,
    bind는 this가 새롭게 바인딩한 함수(원본 함수의 복제본)를 반환함

    • bind를 통해 생성된 함수의 this는 최초의 바인딩 된 객체로 고정됨
    • 다시 명시적으로 바인딩해도 this는 바뀌지 않음

4. new 바인딩

  • new 키워드로 생성자 함수를 이용해 함수를 만들 수 있음

  • this는 빈 객체가 됨

  • 함수 내부에서 this 키워드로 속성과 값을 할당한 뒤,
    this를 출력하면 정의한 속성이 객체 형태로 출력됨

function foo () {
    this.age = 100;
    console.log(this);	// {age:100}
    return 3;	// return 문을 무시함
}

var a = new foo();
console.log(a);	// {age:100}
  • 만약 생성자 함수가 객체를 리턴한다면, this 객체 대신 해당 객체가 리턴됨
function foo () {
    this.age = 100;
    return { haha: 23232 };
}
var a = new foo();
console.log(a);
  • new 바인딩의 동작 순서
function foo () {
    this.age = 100;
}

var a = new foo();
console.log(a);	// {age:100}


// 1. 새 객체가 만들어짐
var obj = {};

// 2. 새로 생성된 객체의 Prototype 체인이 함수의 프로토타입과 연결됨
Obejct.setPrototypeOf(obj, foo.prototype);

// 3. obj 객체를 context 객체로 사용 (명시적)
foo.call(obj, 2);

// 4. foo 함수가 객체를 반환하지 않는 한 obj가 반환됨
var b = obj;

console.log(b.age);	// 100

this 바인딩 우선 순위

new 바인딩 >= 명시적 바인딩 >>>>> 암시적 바인딩 >= 기본 바인딩

  • 암시적 바인딩 vs 명시적 바인딩
function foo(something) {
  this.a = something;
}

var obj1 = {
  foo: foo
};

obj1.foo(2); // 암시
console.log(obj1.a); // 2
// 암시적 바인딩을 통해 obj1 에 a 프로퍼티가 생겨남 (2)

var obj2 = {};

obj1.foo.call(obj2, 3); 
// 암시적 바인딩 된 obj1.foo를 명시적으로 호출
// obj1.foo의 this를 obj2라고 명시, foo의 인자로 3을 줌
// foo가 실행되면서 foo의 this인 obj2에 a 프로퍼티가 생김(3)

console.log(obj1.a); // 2
console.log(obj2.a); // 3
// 명시적 > 암시적
  • 암시적 바인딩 vs new 바인딩
function foo(something) {
  this.a = something;
}

var obj1 = {
  foo: foo
};

obj1.foo(2); // 암시

var obj3 = new obj1.foo(10);
// 암시적 바인딩 된 obj1.foo를 new 키워드로 호출
// 컨텍스트 바인딩이 새로 생성된 객체인 obj3에 적용됨

console.log(obj1.a); // 2
console.log(obj3.a); // 10
// new 바인딩 > 암시적
  • 명시적 바인딩 vs new 바인딩
    • new 바인딩은 새로운 객체를 생성하고, 그 객체를 (명시적) 바인딩함
function foo(something) {
  this.a = something;
}

var obj1 = {};

var bar = foo.bind(obj1); // 명시적 바인딩
bar(2);
console.log(obj1.a); // 2

var baz = new bar(3); // 명시적 바인딩에 new를 시도
console.log(obj1.a); // 2
console.log(baz.a); // 3

Arrow Function

  • 화살표 함수에는 this가 없음
  • 대신 화살표 함수를 둘러싸는 렉시컬 범위의 this가 사용됨!
    바로 바깥 범위에서 this를 찾음
    == 선언된 부분 스코프의 this 컨텍스트를 사용

Reference

1.https://yuddomack.tistory.com/entry/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-this%EC%9D%98-4%EA%B0%80%EC%A7%80-%EB%8F%99%EC%9E%91-%EB%B0%A9%EC%8B%9D

profile
slow and steady wins the race 🐢

0개의 댓글