기술 질문
JavaScript 에서 Function안의 this란?
현재 함수를 부른 객체가 누구인지를 나타내며 고정값이 아닙니다. 함수 내 this는 함수가 호출되는 방식에 따라 결정됩니다.
this는 기본적으로 window임
this; // Window {}
일반 함수 내에서 혼자 this를 선언하면, 그 this는 window 객체를 가리킴
function myFunction() {
console.log(this);
}
myFunction();
객체의 메서드 내에서 this는 그 메서드가 속한 객체를 가리킴
객체 메서드 sayHello 안의 this는 객체 myObject를 가리킴 (호출 시 내부적으로 바꿔줌)
const myObject = {
name: '민혁',
sayHello: function() {
console.log(this.name);
}
};
myObject.sayHello();
but, 아래처럼하면??
var sayHello2 = myObject.sayHello()
sayHello2();
이 경우 sayHello2는 myObject.sayHello 메서드의 참조를 변수에 할당한거임
이 할당된 함수 sayHello2는 독립적인 함수가 되고, myObject 객체와 연결되어 있지 않음
따라서 전역으로 sayHello2를 호출하면, this는 기본적으로 전역 객체(window)를 참조함.
브라우저 환경에는 당연히 name이라는 속성이 없고, 따라서 undefined를 출력함
대강 봤을때, JS에서 함수 내 this는 함수가 호출되는 방식에 따라 결정된다는 걸 알 수 있음.
.
.
.
function getThis() {
return this;
}
const obj1 = { name: "obj1" };
const obj2 = { name: "obj2" };
obj1.getThis = getThis;
obj2.getThis = getThis;
console.log(obj1.getThis()); // { name: 'obj1', getThis: [Function: getThis] }
console.log(obj2.getThis()); // { name: 'obj2', getThis: [Function: getThis] }
obj1.getThis()와 obj2.getThis()는 각각 obj과 obj2를 this로 참조
함수가 객체의 프로토타입 체인 상에서 호출될 때도, this는 호출하는 객체를 참조함
const obj1 = {
name: "obj1",
getThis() {
return this;
},
};
const obj3 = {
__proto__: obj1,
name: "obj3",
};
console.log(obj3.getThis()); // { name: 'obj3' }
JS의 모든 객체는 다른 객체를 참조하는 프로토타입을 가질 수 있음
예제에서 obj3는 obj1을 프로토타입으로 설정함. 이를 통해 obj3은 obj1의 속성과 메서드를 상속받음
작동방식
- JS엔진은 obj3객체에서 getThis를 찾으려고 시도
- 없으니까, JS엔진은 obj3의 프로토타입인 obj1로 가서 getThis를 찾음
strict mode에서는 다음과 같은 상황에 애초에 this가 undefined를 가리킴
strict mode가 아닐경우, this는 기본적으로 전역 객체를 가리킴
strict mode에서 this가 undefined를 가리키는 이유
: 코드 작성자가 의도치 않게 전역 객체의 속성을 수정하거나 접근할 수 있기 때문
strict mode
function logThis() {
"use strict";
console.log(this); // 100
}
[1, 2, 3].forEach(logThis, 100); // 100, 100, 100
this가 명시적으로 설정되지 않으면 undefined가 되지만, 여기서는 thisArg를 사용함.
그래서 thisArg로 설정된 값(100)이 this로 사용됨
non strict mode
function logThis() {
console.log(this); // 100
}
[1, 2, 3].forEach(logThis, 100); // [Number: 100],[Number: 100],[Number: 10
여기서는 this가 전역인 window 값이지만 thisArg를 사용함으로서, thisArg(100)는 Number객체로 변환됨
이게 가능한 이유
배열의 반복 메서드(forEach
, map
, filter
등)와 Set.prototype.forEach()
메서드는 thisArg
매개변수를 받아 콜백 함수의 this
값을 설정할 수 있음
JSON.parse
와 JSON.stringify
의 콜백
const json = '{"name":"Alice","age":25}';
const parsed = JSON.parse(json, function(key, value) {
console.log(this); // 'this'는 현재 처리 중인 객체
return value;
});
const obj = { name: "Bob" };
const jsonString = JSON.stringify(obj, function(key, value) {
console.log(this); // 'this'는 obj
return value;
});
JSON의 parse
와 stringify
메서드는 콜백의 this를 처리 중인 객체로 설정함
- 상위 스코프의 this를 그대로 사용함
- 자기 자신만의 this를 가지지 않음
- 화살표 함수가 정의된 위치의 this를 그대로 사용
즉, 화살표 함수가 만들어질때의 this를 기억하고, 그 값을 계속 사용함
화살표함수는 어떻게 호출을 하던 this가 바뀌지 않음.
this는 항상 함수가 정의될때의 상위 스코프의 this를 유지
const cat = {
name: 'meow';
callName: () => console.log(this.name);
}
cat.callName(); // undefined
callName메소드의 this는 자신을 호출한 객체 cat이 아니라 함수 선언 시점의 상위 스코프, 즉 전역객체를 가리킴.
(strictmode라면 undefined이고, non strictmode라면 window일거임!)
따라서 저럴 경우는 일반 함수로 callName을 선언해야됨
기본 생성자 함수: new와 함께 호출하면, 새 객체가 만들어지고 this는 그 새 객체를 가리킴
function C() {
this.a = 37; // 새로 만들어진 객체에 'a'라는 프로퍼티를 37로 설정
}
let o = new C(); // 'new'를 사용해 C 함수 호출
console.log(o.a); // 37
객체 반환: 생성자 함수가 객체를 반환하면, 새로 만든 객체 대신 반환된 객체가 사용됨
.
.
.
끝🫠