코르시카 2021. 4. 15. 17:40

■ Js This의 범위

1) 영향을 주는 것

(a) 엄격 / 비엄격

엄격 / 비엄격은 global 또는 block 안에서 각각 선언할 수 있음

(b) 함수의 호출방식

(c) 화살표 함수 사용 여부

 

2) this의 정의

실행 컨텍스트( global, function, eval )에 따라 달라짐

또한 엄격 / 비엄격에 대해서 다음과 같음

  비엄격 모드 엄격 모드
this 항상 객체 그 어떤 값도 가능

※ 실행 컨텍스트이므로, runtime때 dynamic하게 바뀜!

 

 

■ 문맥

1) 기본 바인딩 -  전역 문맥

global execution context, this는 엄격 / 비엄격 모드 관계 없이 전역 객체 참조

// 웹 브라우저에서는 window 객체가 전역 객체
console.log(this === window); // true

a = 37;
console.log(window.a); // 37

this.b = "MDN";
console.log(window.b)  // "MDN"
console.log(b)         // "MDN"

2) 함수 문맥

함수 안에서의 this는 함수의 주인에게 바인딩 됨.

 

(a) 비엄격 모드

>  this의 값이 호출에 의해 설정되지 않았음

function f1() {
  return this;
}

// 브라우저
f1() === window; // true

// Node.js
f1() === global; // true

(b) 엄격모드

>  this 값이 실행 문맥에 진입( global scope이 아닌 block으로 )

> default 바인딩이 없어서 undefined 결과 생김

function f2(){
  "use strict"; // 엄격 모드 참고
  return this;
}

f2() === undefined; // true

3) 매써드 문맥 - 객체의 매써드

함수가 객체의 매써드로 사용되어 호출되면, 그 해당함수 내부에서의 this는 호출한 객체

	
var person = {
  firstName: 'John',
  lastName: 'Doe',
  fullName: function () {
    return this.firstName + ' ' + this.lastName; //this 는 person
  },
};
 
person.fullName(); //"John Doe"

> 외부에서 정의된 함수를 불러와도 this가 context때문에 변경 됨

var num = 0;
 
function showNum() {
  console.log(this.num);
}
 
showNum(); //0
 
var obj = {
  num: 200,
  func: showNum,
};
 
obj.func(); //200

> 매써드 안의 내부 함수의 경우 this 바인딩이 다름

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

> 매써드의 내부함수 binding work-around 방법

var value = 1;

var obj = {
  value: 100,
  foo: function() {
    var that = this;  // Workaround : this === obj

    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

      console.log("bar's that: ",  that); // obj
      console.log("bar's that.value: ", that.value); // 100
    }
    bar();
  }
};

obj.foo();

4) Event hander 문맥

> 3의 메써드 문맥의 연장선

var btn = document.querySelector('#btn')
btn.addEventListener('click', function () {
  console.log(this); //#btn
});

5) 생성자 문맥

new 키워드를 통해 생성했을 시 "생성자 함수" 객체에 this가 binding 됨

function Person(name) {
  this.name = name;
}
 
var kim = new Person('kim');
var lee = new Person('lee');
 
console.log(kim.name); //kim
console.log(lee.name); //lee

※ new를 쓰지 않으면 일반 함수와 다를 것이 없으므로, window로 this가 binding 됨

var name = 'window';
function Person(name) {
  this.name = name;
}
 
var kim = Person('kim');
 
 //전역 window의 프로퍼티 name의 변경
console.log(window.name); //kim

6) Arrow function의 this

추가 참조 : Link

Arrow function의 this는 항상 정적으로 상위 scope의 this를 가르킨다 (lexical this)

const Person = () => {
  this.age = 0;
  console.log(this.age); // 0

  setTimeout(() => {
    this.age++; // 1
    console.log(this.age); // 1
  }, 1000);
}

Person();

>>>
1

7) 명시적 binding의 this

apply, call, bind 매써드

- apply : Obj + array

- call : Obj + param

- bind : Obj + tuple param for function activation

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(a, b) {
      console.log("bar's this: ",  this); // obj
      console.log("bar's this.value: ", this.value); // 100
      console.log("bar's arguments: ", arguments);
    }
    
    // 내부함수로 호출이지만, 명시적으로 binding 해줘서 this가 obj로 바뀜
    bar.apply(obj, [1, 2]);
    bar.call(obj, 1, 2);
    bar.bind(obj)(1, 2);
  }
};

obj.foo();

※ bind 매써드

추가 참조 : developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

 

Function.prototype.bind() - JavaScript | MDN

Function.prototype.bind() bind() 메소드가 호출되면 새로운 함수를 생성합니다. 받게되는 첫 인자의 value로는 this 키워드를 설정하고, 이어지는 인자들은 바인드된 함수의 인수에 제공됩니다. func.bin

developer.mozilla.org

> bind에 thisArg로 binding할 this 이외의 arg들은 해당 함수 앞에 차례로 argument로 들어가게 됨

> binding 예시

function list() {
  return Array.prototype.slice.call(arguments);
}

var list1 = list(1, 2, 3); // [1, 2, 3]

// 선행될 인수를 설정하여 함수를 생성합니다.
var leadingThirtysevenList = list.bind(null, 37); //list라는 함수 인자 맨 앞에 37 추가

var list2 = leadingThirtysevenList();  // [37]

var list3 = leadingThirtysevenList(1, 2, 3);  // [37, 1, 2, 3]

 


> 활용 방법

(1)예시로 동일한 매써드 존재할 때

// 다음과 같이 겹치는 property가 있을 때

function Character(name, level) {
  this.name = name;
  this.level = level;
}
 
function Player(name, level, job) {
  this.name = name;
  this.level = level;
  this.job = job;
}
function Character(name, level) {
  this.name = name;
  this.level = level;
}
 
function Player(name, level, job) {
  Character.apply(this, [name, level]); // binding을 new를 사용하여 Player의 this에 binding 하여
                                        // Character 의 this가 Player의 this로 치환됨
                                        // Property가 같아서 이런식으로 사용가능
  this.job = job;
}
 
var me = new Player('Nana', 10, 'Magician');

(2) 유사 array의 array화

> 원래는 error 때문에 array 매써드들 사용 못함

// Error case
function func(a, b, c) {
  console.log(arguments);
 
  arguments.push('hi!'); //ERROR! (arguments.push is not a function);
}

// No-error case
function func(a, b, c) {
  var args = Array.prototype.slice.apply(arguments);
  args.push('hi!');
  console.dir(args);
}
 
func(1, 2, 3); // [ 1, 2, 3, 'hi!' ]

7) 화살표 함수와 this

전역 컨텍스트에서 실행되더라도, 부모 함수 / 생성자 함수(클래스)의 this로 바인딩 됨

> Error case

var Person = function (name, age) {
  this.name = name;
  this.age = age;
  this.say = function () {
    console.log(this); // Person {name: "Nana", age: 28}
 
    setTimeout(function () {
      console.log(this); // Window
      console.log(this.name + ' is ' + this.age + ' years old');
    }, 100);
  };
};
var me = new Person('Nana', 28);
 
me.say(); //global is undefined years old ///////// <- not wanted case

> Right case

	
var Person = function (name, age) {
  this.name = name;
  this.age = age;
  this.say = function () {
    console.log(this); // Person {name: "Nana", age: 28}
 
    setTimeout(() => {
      console.log(this); // Person {name: "Nana", age: 28}
      console.log(this.name + ' is ' + this.age + ' years old'); 
    }, 100);
  };
};
var me = new Person('Nana', 28); //Nana is 28 years old

참조 :

developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/this

 

this - JavaScript | MDN

this JavaScript에서 함수의 this 키워드는 다른 언어와 조금 다르게 동작합니다. 또한 엄격 모드와 비엄격 모드에서도 일부 차이가 있습니다. 대부분의 경우 this의 값은 함수를 호출한 방법에 의해 

developer.mozilla.org

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

 

javascript this의 4가지 동작 방식

이번 글에서는 자바스크립트 this가 어떻게 동작하는지 알아보겠습니다. 프로토타입을 먼저 쓸지, this를 먼저 쓸지 고민했는데 아무래도 this가 좀 더 쉬울 것 같네요 1. 오해 흔히(java에서) 클래

yuddomack.tistory.com

nykim.work/71

 

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

this는 이것을 뜻합니다! (그러니까 '이게' 뭐죠...... 😵) 자바스크립트 내에서 this는 '누가 나를 불렀느냐'를 뜻한다고 합니다. 즉, 선언이 아닌 호출에 따라 달라진다는 거죠. 그럼 각 상황별로 th

nykim.work

poiemaweb.com/js-this

 

this | PoiemaWeb

자바스크립트의 this keyword는 Java와 같은 익숙한 언어의 개념과 달라 개발자에게 혼란을 준다. Java에서의 this는 인스턴스 자신(self)을 가리키는 참조변수이다. this가 객체 자신에 대한 참조 값을

poiemaweb.com

 

반응형