this
- 자바스크립트의 프로토타입 모델
자바스크립트에선 객체가 생성되면 새로운 객체 콘텐츠의 일부 혹은 전체를 가지는 프로토타입이 지정됩니다.
const newObject = Object.create(oldObject);
객체는 속성만 저장하며, 메서드는 객체에 저장된 함수에 불과하고 프로토타입은 객체일 뿐입니다.
객체가 가지고 있지 않은 속성의 값을 얻으려고 하면 그 값은 undefined 입니다. 하지만 객체가 위의 newObject 처럼 프로토타입을 갖고 있는 경우 결과 값은 프로토타입의 속성 값이 됩니다. 이렇게 체인 형식으로 프로토타입이 더 이상 없을 때까지 반복됩니다.
- 프로토타입을 사용하는 가장 큰 이유 중 하나는 메서드를 저장하는 공간으로 쓰기 위함입니다.
비슷한 객체들이 전부 비슷한 메서드를 가지는 경우가 많기 때문에 이런 메서드들을 하나의 공유 프로토타입에 저장한다면 메모리를 절약할 수 있습니다.
- this
프로토타입에 있는 함수가 어떤 객체에서 동작하고 있는지 알아내기 위해 this 를 사용합니다.
지정된 이름의 메서드를 찾기 위해 객체와 프로토타입 체인을 검색하고, 메서드를 찾지 못하면 예외가 발생합니다.
메서드가 발견되면 인자 목록을 건네 메서드를 호출합니다. 그리고 메서드는 자신을 동작시킨 객체에 대한 정보를 this 라는 묵시적 매개변수로 전달받습니다.
메서드 안에 내부 함수가 있다면 그 함수는 그냥 함수로서 호출되는 것이므로 this 에 접근할 수 없습니다.
메서드 호출만 this 바인딩을 제공받습니다.
oldObject.bud = function bud() {
const that = this;
// lou 함수는 bud 메서드의 this 를 볼 수 없기에 bud 의 this 를 변수에 저장해서 사용하는 방법
function lou() {
console.info(that);
console.info(this);
}
lou();
};
oldObject.bud();
// { bud: [Function: bud] }
// Object [global] { ... }
하지만 ES6 부터 등장한 화살표함수를 사용하면 that 과 같은 별도의 변수를 사용하지 않아도 되긴 합니다.
화살표함수가 가리키는 this 는 상위 스코프의 this 와 같기 때문입니다.
oldObject.bud = function bud() {
const lou = () => {
console.info(this);
};
lou();
};
oldObject.bud(); // { bud: [Function: bud] }
일반 함수에선 this 가 동적으로 바인딩된다는 점이 독특합니다. 다른 모든 변수들은 정적으로 바인딩되기에 혼란을 불러올 수 있습니다.
- this 는 보안이나 신뢰성 위험을 초래할 수 있습니다.
- 함수 객체는 두 개의 프로토타입 속성을 갖고 있습니다.
하나는 Function.prototype 에 대한 델리게이션 링크입니다.
다른 하나는 new 접두어로 함수가 호출되어 객체가 생성된 경우 생성된 객체의 프로토타입으로 사용된 객체에 대한 참조를 prototype 이라는 속성으로 가집니다.
- new 접두사가 하는 일
- Object.create(function.prototype) 에 대한 this 값을 만듦
- 새로운 객체에 바인딩된 this 값으로 함수를 호출
- 함수가 객체를 반환하지 않으면 this 를 강제로 반환
모든 함수가 잠재적으로 생성자처럼 사용될 수 있으므로 어떤 함수에 new 접두사를 붙여서 호출해야 하는지 알아내는 것은 어렵습니다.
new 접두사를 써야 하는데도 쓰지 않았을 경우, 아무런 경고도 없다는 것 또한 문제점입니다.
(아래 예시의 주석처리 된 부분을 실제 호출해도 아무런 경고가 발생하지 않음)
function Student(name) { // 생성자 함수는 대문자로 시작
this.name = name;
this.info = function info() {
console.info('name :', this.name);
}
}
// Student('peter'); -> X (일반 함수처럼 호출하지 않는다)
const student = new Student('peter');
student.info(); // name : peter
- 그래서 위 예시처럼 new 접두사를 써서 호출해야 하는 생성자 함수는 대문자로 시작해야 한다는 관습이 생겼습니다.
다른 함수들은 대문자로 시작해서는 안됩니다. 여기에 추가로 더 평범해 보이는 class 문법을 자바스크립트는 제공합니다.
따라서 class 또한 대문자로 시작해야 합니다.
class Student {
constructor(name) {
this.name = name;
}
info() {
console.info('name :', this.name);
}
}
const student = new Student('peter');
student.info(); // name : peter
하지만 자바스크립트에서 class 문법은 실제로 클래스를 구현하지는 않습니다. 기존에 사용하던 생성자 함수의 이상함을 감추고 좀 더 문법을 쉽게 사용하게 만든 syntactic sugar (문법적 설탕) 일 뿐입니다.
- this 관리
메서드 호출에서는 사용되는 객체가 this 로 바인딩되기 때문에 this 가 때때로 쓸모있지만, 함수로서 호출되면 this 는 전역 객체에 바인딩 될 수 있으므로 좋지 않습니다.
일부에선 자바스크립트에서 this 를 아예 사용하지 않는 방법도 제시하곤 하지만 실무에선 100% 적용하기엔 어렵다고 생각합니다.
일반 함수 사용 시에는 this 를 빼버리거나 (실제로 쓸 일도 없긴 합니다),
필요한 경우 혼란을 막기 위해 화살표 함수를 사용하는 것이 좋아 보입니다.
출처 : 자바스크립트는 왜 그 모양일까?
'Backend > Javascript' 카테고리의 다른 글
[Javascript] - Asynchronous Programming (0) | 2021.01.09 |
---|---|
[Javascript] - Purity (0) | 2021.01.02 |
[Javascript] - Exception (0) | 2020.12.12 |
[Javascript] - Generator (0) | 2020.12.05 |
[Javascript] - Function (0) | 2020.11.28 |