JS this

강정우·2022년 10월 6일
0

JavaScript

목록 보기
16/53
post-thumbnail

this가 가리키는 것

  • 함수가 상황에 따라 4가지로 다르게 호출된다.
  1. 함수호출 : 함수를 직접 호출
myFunc()
  1. 메서드호출 : 객체의 메서드를 호출
o.method()
  1. 생성자 호출 : 생성자 함수를 호출
Function Person(){
	this.name = 'abc'
}

const p = new Person()
  1. 간접 호출 : function 객체를 상속받는 call, apply, bind 등으로 함수를 간접 호출한다.
function.call(null, a)
  • 또한 문법적 호출 외에 콜백함수의 호출이 있다.
  • 콜백함수는 특정 동작이후에 불려지는 함수이다.
  • 보통 다른 함수의 인자로 보내지는 함수를 의미한다.
function callback(){
	console.log('xxx')
}
function myFunc(name, callback()){
	console.log('name :' , name)
    callback(name)
}
myFunc('Daniel', callback)
setTimeout(function(){...})
  • 위의 setTimeout 함수도 콜백함수를 사용하는 함수이다.

dynamic binding

function myFunc(){
	console.log('myFunc called')
}

// 1. 함수 직접 호출
myFunc() 

const o ={
	name : 'Daniel',
    printName : function(){
    	console.log(this.name)
    }
}
// 2. 객체의 함수를 호출 => 이때 this값이 객체를 가르킴
o.printName()

function Person(name){
	this.name = name
    this.printName = function(){
    	console.log(this.name)
    }
}

// 3. 생성자 호출
const p = new Person('Daniel')

// 4. 간접 호출
setTimeout(p.printName.bind(p), 1000)
  • 4번에 bind를 쓰면 this 값이 매개변수의 값을 갖도록 함.

정리

  • 함수는 이렇듯 다양한 환경(상황)에서 호출될 수 있다.
  • 함수의 호출 환경에 따라 this는 동적으로 세팅된다.
  • 이렇게 this가 환경에 따라 바뀌는 것을 동적 바인딩이라고 한다. 이때 동적으로 this를 바꿀 수 있는 함수가 bind()이다.
  • bind, apply, call 등으로 this가 가리키는 것을 조작할 수 있다.

화살표 함수와 일반 함수의 차이

let o = {
	name : "Daniel",
    f1 : () => {
    	console.log("[f1] this : ", this);
    },
    f2 : function(){
    	console.log("[f2] this : ", this);
    },
};

o.f1(); // global
o.f2(); // o

setTimeout(o.f1, 10); // global
setTimeout(o.f2, 10); // global
  • f1은 화살표 함수로 호출 시 this는 함수가 생성된 환경을 가리키도록 고정된다.
  • f2는 일반함수로 this는 함수로 호출된 환경을 가리키며 this는 동적으로 바뀔 수 있다.
  • f2는 객체의 메서드로 호출될 때 객체가 this로 할당된다.
let o = {
	name : "Daniel",
    printNAme : function(){
    	console.log("내 이름은 ", this.name);
    },
};

o.printName(); // 내 이름은 Daniel
setTimeout(o.printName, 10);  // 내 이름은 Undefined
setTimeout(o.printName.bind(o), 20);  // 내 이름은 Daniel
  • 위 코드를 보면 그냥 객체의 메서드를 실행할 땐 this가 o를 가르키고 있기 때문에 Daniel이 잘 실행되는 것을 확인할 수 있다. 하지만 setTimeout() 메서드 안에 들어오면 this가 없기 때문에 undefined가 나온다. 이에 this를 변경해줄 수 있는 것이 바로 bind()이다.

정리

  • bind, call, apply 등의 함수로 this를 조작한다.
  • setTiimeout은 함수 호출과는 다른 콜백 호출이다.
  • printName method는 bind 함수를 이용해 this 변수가 o를 가리키도록 컨텍스트를 동적 바인딩한다.

화살표 함수 VS 일반함수 의 this

  • 화살표 함수의 this는 호출된 함수를 둘러싼 실행 컨텍스트를 가리킨다.
  • 일반 함수의 this는 새롭게 생성된 실행 컨텍스트를 가리킨다. 이때 stack에 계쏙 쌓이게 되는데 너무 많은 양의 stack을 쌓게 되면 이때 발생하는 오류가 바로 stack overflow이다.
const o = {
	method(){
    	console.log("context :", this)  // o
        let f1 = function(){
        	console.log("[f1] this :", this)
        }
        let f2 = () => 
        	console.log("[f2] this :", this)
           f1()  // global
           f2()  // o
    },
};

o.method()
  • f1()은 실행될 때 새로운 컨텍스트를 생성한다.
  • 이래 f1에 바인딩된 컨텍스트가 없으므로 this는 global을 가리킨다. 이때 만약 use strict mode를 쓰게 된다면 undefined를 가르킬것이다.
  • f2()는 함수 컨텍스트를 생성하며 this 변수는 부모의 컨텍스트를 가리킨다.
  • 따라서 this는 o가 된다.

정리

  • 화살표 함수의 this는 정해지면 바꿀 수 없다.
  • call, bind, apply를 사용해도 바뀌지 않는다.
  • setTimeout등 this가 바뀌는 상황에서 유용하다.

예제 코드

window.name = 'Daniel'
let o = {name : 'Kim'}

let arrowFunction = (prefix) => console.log(prefix + this.name)

arrowFunction('Dr. ')  //  Dr. Daniel
arrowFunction.bind(o)('Dr. ')  //  Dr. Daniel
arrowFunction.call(o, 'Dr. ')  //  Dr. Daniel
arrowFunction.apply(o, ['Dr. '])  //  Dr. Daniel
  • 보면 bind 함수로 인하여 o의 context로 객체가 binding되어야 할 것 같지만 화살표 함수이기에 함수에서 지정해준 값이 나온 것을 볼 수 있다.

브라우저 메서드에서 함수 전달방법

.bind

const button = document.querySelector('button');

function clickHandler(message) {
    console.log('Clicked ' + message + ' by ' + this.name);
}

const user = {
  name: 'John'
};

if (button) {
    button.addEventListener('click', clickHandler.bind(user, '안녕'));
}

()=> wrapper

const button = document.querySelector('button');

function clickHandler(message) {
    console.log('Clicked ' + message);
}

if (button) {
    button.addEventListener('click', () => clickHandler('안녕'));
}

.bind vs ()=> wrapper

  • 이 둘은 무슨 차이가 있을까? =>

bind 메서드와 화살표 함수는 함수를 다른 방식으로 호출하고 함수 컨텍스트를 설정하는 데 사용될 수 있다.
그러나 두 가지 접근 방식은 기능적으로 다르다.

1. 인자 전달 방식

  • bind 메서드를 사용하여 함수를 호출할 때, 함수에 전달할 인자를 미리 설정할 수 있다.
    bind 메서드는 함수에 전달할 인자를 설정하는 매개변수(this)를 앞쪽에 고정시키고, 나중에 호출될 때 전달되는 인자와 함께 실행되도록 한다.
    이는 함수에서 this에 사용될 인자 값을 미리 설정하고, 함수 호출 시에는 추가적인 인자를 전달할 수 있는 유연성을 제공한다.

2. 함수 컨텍스트

  • bind 메서드를 사용하여 함수를 호출할 때, 첫 번째 인자로 전달한 객체는 해당 함수 내부에서 this로 참조된다. 이는 함수의 실행 컨텍스트를 설정하는 데 사용되는데 bind 메서드를 사용하여 함수에 컨텍스트를 바인딩하면, 해당 함수가 호출될 때 항상 지정한 컨텍스트 객체를 this로 사용한다.
function sayName() {
  console.log('My name is ' + this.name);
}

const person = {
  name: 'John'
};

const boundSayName = sayName.bind(person);

boundSayName(); // 출력: "My name is John"

화살표 함수

  • 반면에 화살표 함수는 자체적인 컨텍스트를 갖지 않으며, 화살표 함수 내부에서 this는 상위 스코프의 this 값을 상속받는다.
    화살표 함수는 렉시컬 스코프를 사용하므로, 함수를 정의한 시점에서의 외부 스코프의 this 값을 사용한다.

  • 따라서, bind 메서드를 사용하여 함수에 인자를 전달하고 컨텍스트를 설정하는 것은 함수의 동작 방식을 변경시키는 것이다.
    반면에 화살표 함수를 사용하여 이벤트 리스너 콜백으로 전달하는 것은 함수의 실행 컨텍스트를 상위 스코프로부터 상속받는 것이다.

profile
智(지)! 德(덕)! 體(체)!

0개의 댓글