Core js - this

heyhey·2023년 10월 27일
0
post-thumbnail

1 상황에 따라 달라지는 this

다른 객체지향 언어에서 this는 클래스로 생성한 인스턴스 객체를 의미합니다.
하지만 JS에서의 This는 어디서든 사용할 수 있습니다.

상황에 따라 this 가 바라보는 대상이 달라지게 됩니다.

JS에서 this는 기본적으로 실행 컨텍스트가 생성될 때 함께 결정됩니다.
이 실행 컨텍스트는 함수를 호출할 때 생성됩니다.
그래서 this는 '함수를 호출할 때 결정됩니다'

1-1 전역 공간에서의 This

전역 공간에서의 this는 전역 객체입니다.
컨텍스트를 생성하는 주체가 전역 객체이기 때문입니다.

브라우저 - window
node 환경 - global

전역 변수를 선언하면 JS 엔진은 이를 전역 객체의 프로퍼티로 할당합니다.
변수이면서 객체의 프로퍼티이기도 합니다.

JS 의 모든 변수는 실은 특정 객체의 프로퍼티로서 동작합니다.
여기서의 특정 객체는 Lexical Environment 입니다.
실행 컨텍스트는 변수를 수집하여 L.E의 프로퍼티로 저장합니다.

var a = 1;
console.log(a) // 1
console.log(this.a) // 1
console.log(window.a) // 1

변수 a 에 접근하고자 하면 스코프 체인에서 a를 검색하다가 가장 마지막에 도달하는 전역객체의 a를 발견하여 반환하기 때문입니다.
(전역 객체에서의 This는 Window 입니다)

delete 연산자를 쓰는 부분에서 선언과 할당에서 이상한 부분이 생깁니다.
처음부터 전역객체의 프로퍼티로 할당할 경우 (window.a = 1)는 삭제가 됩니다
하지만 전역 변수를 선언하게 되면, 삭제가 되지 않습니다.

JS 엔진이 의도치 않게 삭제하는 것을 방지하기 위해 해당 프로퍼티의 configurable 속성을 false로 정의하기 때문입니다.

1-2 메서드로서 호출할 때 그 메서드 내부에서의 this

함수를 호출하는 방식은, 함수로 호출, 메서드로 호출 두가지 방법이 있습니다.
fun() / obj.fun()
함수는 그 자체로 독립적인 기능을 수행하지만 메서드는 자신을 호출한 대상 객체에 관한 동작을 수행하게 됩니다.

메서드 내부에서의 this

this 에는 호출한 주체에 대한 정보가 담깁니다.
어떤 함수를 메서드로서 호출하는 경우 호출 주체는 점 앞의(.)객체입니다.

1-3 함수로서 호출할 때 그 함수 내부에서의 this

함수를 호출할 경우에는 this 가 지정되지 않습니다.
this는 호출한 주체에 대한 정보가 담깁니다. 그러나 함수 호출은 객체를 명시하지 않고 실행했기 때문에 호출 주체의 정보를 알 수 없습니다.
따라서 함수에서의 this 도 전역 객체를 바라보게 됩니다.

예시를 통해 외웁니다.

var obj1 = {
	outer : function(){
		console.log(this) // 1) 
		var inner = function(){
			console.log(this) // 2) 3)
		}
		inner();
		var obj2 = {
			innerMethod : inner
		}
		obj2.innerMethod(); 
	}
}
obj1.outer ; // 3) 

결과는 1) obj1, 2) window, 3) obj2 입니다.

내부 함수에서의 this를 우회하는 방법

내부 함수에서 This를 상속할 방법은 없습니다.
상위 스코프의 this를 저장해서 내부 함수에서 활용하고 싶을 때는 우회해야 합니다.
가장 많이 사용하는 법은 변수를 사용해서 저장해서 사용하는 법입니다.
self = bind

ES6 에서는 함수 내부에서 This 가 전역객체를 바라보는 문제를 보완했습니다. 그것이 화살표 함수 입니다.
화살표 함수는 실행 컨텍스트를 생성할 때 This 바인딩 자체가 빠지게 되어 상위 스코프의 This를 그대로 활용할 수 있습니다.

1-4 콜백 함수 호출 시 그 함수 내부에서 this

함수 A의 제어권을 다른 함수 B에게 넘겨주는 경우 함수 A를 콜백함수라고 합니다. this 역시 함수 B 내부 로직에서 정한 규칙에 따라 값이 변경됩니다.

콜백함수의 예시들을 보며 익혀봅시다.


setTimeout(function(){console.log(this)},300)

[1,2,3,4,5].forEach(function(x){
	console.log(x,this)
})

document.body.innerHTML += '<button id='a'>클릭</button>'
document.body.querySelector('#a')
				.addEventListener('click',function(e){
					console.log(this,e)
				})

이렇게 세가지의 경우가 있습니다.
1 번의 경우 전역 객체가 출력됩니다.
2 번의 경우도 전역객체가 출력됩니다.
3 번의 경우는 엘리먼트의 정보가 출력됩니다. ??
addEventListener 메서드는 콜백 함수를 호출할 때 자신의 This를 상속하도록 정의가 되어있기 때문입니다.

1-5 생성자 함수 내부에서의 this

객치지향 언어는 생성자를 클래스, 클래스를 통해 만든 객체를 인스턴스 라고 합니다.
생성자는 구체적인 인스턴스를 만들기 위한 일종의 틀입니다.

JS에서 new 명령어와 함수를 호출하면 함수가 생성자로서 동작합니다.
여기서의 this는 새로 만들 인스턴스 자신이 됩니다.

생성자 함수를 호출하면 인스턴스가 만들어 지는 과정입니다.
prototype 프로퍼티를 참조하는 __proto__ 라는 프로퍼티가 있는 객체를 만듭니다.
미리 준비된 공통 속성 및 개성을 해당 객체에 부여합니다.

2 명시적으로 this를 바인딩하는 법

This에 별도의 대상을 바인딩하는 방법도 있습니다.

2-1 call 메서드

메서드의 호출 주체인 함수를 즉시 실행하도록 하는 명령어입니다.
이 때 call 메서드의 첫 번째 인자를 this로 바인딩하고, 이후의 인자들을 호출할 함수의 매개변수로 합니다.
call 메서드는 첫번째 인자를 제외한 모든 인자들을 매개변수로 지정합니다.

함수를 그냥 실행하면 This는 전역객체를 참조하지만, call 메서드를 이용하면 임의의 객체를 This로 지정합니다.

사용법

var func = function(a,b,c){
	console.log(this)
	console.log(a,b,c)
}
func.call({x:1},4,5,6) // {x:1}  /n 4 5 6

2-2 apply 메서드

call 메서드와 기능적으로 동일합니다.
call 메서드는 첫번째 인자를 제외한 모든 인자들을 매개변수로 지정하는 반번
Apply 매서드는 두번째 인자를 배열로 받습니다.

var func = function(a,b,c){
	console.log(this)
	console.log(a,b,c)
}
func.apply({x:1},[4,5,6]) // {x:1}  /n 4 5 6

2-3 call/apply 메서드 활용

유사 배열 객체에 배열 메서드를 적용

var obj = {
	0:'a',
	1:'b',
	2:'c',
	length : 3
}
Array.prototype.push.call(obj,'d')
console.log(obj) = {=0:'a',1:'b',2:'c',3:'d',length:4}

var arr = Array.prototype.slice.call(obj) // 객체를 배열로 전환
console.log(arr) // [a,b,c,d,]

키가 양의 정수(0도 가능)인 프로퍼티가 존재하고, Length 길이도 0이상 일 경우에는 call 또는 apply 를 활용해 배열 매서드를 차용할 수 있습니다.

이러한 기능은 ES6에서 Array.from 메서드를 통해 대체되었습니다.

생성자 내부에서 다른 생성자 호출


function Person (name,gender){
	this.name = name
	this.gender = gender
}

function Student(name,gender,school){
	Person.call(this,name,gedner);
	this.school = school
}

여러 인수를 묶어 하나의 배열로 전달하고 싶을 때

var numbers = [11,2,3,4,5,5]
var max = Math.max.apply(null,numbers)

apply 를 이용해 Math의 max에 적용할 수 있습니다.
ES6에서는 spread 연산자를 통해 사용 가능합니다.
const max = Math.max(...numbers)

2-4 bind 메서드

bind 는 ES5에서 추가된 기능으로 call 과 비슷하지만 즉시 호출하지 않고 넘겨 받은 this 및 인수들을 바탕으로 새로운 함수를 반환하는 메서드입니다.
var bindFunc = func.bind({x:1})

name 프로퍼티

Bind 메서드를 통해 만든 함수는 name 프로퍼티에 bound 라는 접두어가 붙습니다. bound func

상위 컨텍스트의 This를 내부함수나 콜백 함수에 전달하기

앞서 내부함수에서 this를 그대로 바라보게 하기 위해 변수를 만들었는데 call,apply, bind 를 통해 더 깔끔하게 처리할 수 있습니다.


var obj = {
	outer : function(){
		console.log(this)
		var inner = function(){
			console.log(this)
		}
		inner.call(this)
	}
}
obj.outer()

2-5 화살표 함수의 예외사항

화살표 함수일 경우 실행 컨텍스트 생성 시 this를 바인딩하는 과정이 제외되었습니다.
이 함수 내부에는 This가 아예 없으며 , 접근하고자 하면 스코프 체인상 가장 가까운 this가 접근됩니다.

2-6 별도의 인자로 this를 받는 경우 (콜백 함수 내에서의 this)

배열 메서드 같은 곳에서 많이 사용됩니다.

profile
주경야독

0개의 댓글