-
JavaScript의 this자바스크립트 Study/자바스크립트 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
> 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
반응형'자바스크립트 Study > 자바스크립트' 카테고리의 다른 글
new Keyword in JavaScript (0) 2021.04.17 JS (ES6 & above) - Class & Objects (0) 2021.04.15 Javascript Closure & Lexical Scope (0) 2021.04.13 Javscript Coding convention, guides (0) 2021.04.13 JS (ES6 & above) - Functions (0) 2021.04.13