4.4 함수 호출과 this
- 자바스크립트에서는 함수 형식에 맞춰 인자를 넘기지 않더라도 에러가 안난다.
- 함수의 인자보다 적게 호출하면 넘겨지지 않은 인자에는 undefined가 할당되고 인자 갯수보다 많게 호출하면 나머지는 무시된다.
- arguments 객체는 함수를 호출할 때 넘긴 인자들이 유사 배열 객체로 저장되어 있다.
- 매개변수가 정확하게 정해지지 않은 함수를 구현하거나, 전달된 인자의 갯수에 따라 서로 다른 처리를 해줘야 하는 함수를 개발하는데 유용하게 사용할 수 있다. (ES6 이후부터는 나머지 연산자를 사용해서 구현 가능)
4.4.2 호출 패턴과 this 바인딩
- 함수 호출을 할 때 암묵적으로 arguments 객체와 this 인자가 전달된다.
- this가 이해하기 어려운 이유는 자바스크립트의 여러가지 함수가 호출 되는 방식에 따라 this가 다른 객체를 참고하기 때문이다.
4.4.2.1 객체의 메서드로 호출 시
- 객체의 프로퍼티가 함수인 경우 메서드라고 부른다.
- 이 메서드 내부 코드에서 사용된 this는 해당 메서드를 호출한 객체로 바인딩 된다.
4.4.2.2 함수를 호출할 때 this 바인딩
- 전역에서 함수 호출 시 전역 객체가 this로 바인딩 된다.
- 내부 함수에서 this를 이용할 때는 주의해야 한다.
- 이 책에서는 함수 내부에서 that 이라는 변수에 this를 미리 할당하는 내용이 나오는 데 이건 좀 옛날 방식이다.
- 가장 쉬운 방법은 내부 함수에서 화살표 함수를 사용하는 것이다. 화살표 함수는 호출 방법에 따라 this가 달라지는 게 아니라 만들어질 당시의 스코프에서 this를 기억하고 있기 때문에 내부 함수를 화살표 함수를 사용하면 부모 함수가 가지고 있는 this를 기억하고 있기 때문에 this를 잃어버리지 않는다.
- 단, 객체의 메서드를 화살표 함수로 만들면 안된다. 객체의 메서드로 호출하게 되던 다른 곳에 할당을 하던 간에 객체 메서드에서 화살표 함수를 선언할 당시의 this (보통 전역 객체)를 인식하기 때문이다.
4.4.2.3 생성자 함수를 호출할 때 this 바인딩
- 생성자 함수는 객체를 생성하는 역할을 한다. 기존 함수에 new 연산자를 붙여서 호출하면 해당 함수는 생성자 함수로 동작한다.
- 생성자 함수는 암묵적으로 이름 첫글자를 대문자로 쓴다.
- 생성자 함수가 동작하는 방식은 아래와 같다.
1. 빈 객체 생성 및 this 바인딩
- 함수 내부에서 빈 객체가 생성됨. 이 객체가 생성자 함수가 새로 생성하는 객체이다. 이것이 내부에서 this로 바인딩 된다.
- 이 객체는 자신을 생성한 생성자 함수의 prototype 프로퍼티가 가리키는 객체를 자신의 프로토타입 객체로 설정한다.
2. this를 통한 프로퍼티 생성
- 내부에서 this를 통해 동적으로 프로퍼티나 메서드를 생성할 수 있다.
3. 생성된 객체 리턴
- 리턴문이 없다면 this로 바인딩 된 새로 생성된 객체가 리턴된다. (return this도 마찬가지로 동작)
- 하지만 다른 객체를 리턴하면 생성자 함수 호출을 했어도 this가 아닌 그 객체가 리턴된다. (객체가 아닌 원시값을 리턴할 경우에는 그냥 무시하고 this로 바인딩 된 객체가 제대로 리턴된다. 참조값인 배열, 함수, 객체는 얘네들이 리턴된다.)
4.4.2.4 call과 apply 메서드를 이용한 명시적인 this 바인딩
- this를 특정 객체에 명시적으로 바인딩 시키는 방법이다.
- 본질적으로 함수를 호출하는 방법이다.
- 아래와 같이 사용한다. 인자를 넘겨주는 방식만 다르도 동작은 같다.
function Person(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
const foo = {}
Person.apply(foo, ['foo', 30, 'man'])
Person.call(foo, 'foo', 30, 'man')
4.5 프로토타입 체이닝
4.5.1 프로토타입의 두 가지 의미
- 자바스크립트는 프로토타입 기반의 객체지향 프로그래밍을 지원한다. 클래스 개념이 없다.
- 생성된 객체의 부모 객체가 바로 '프로토타입' 객체다. 자식 객체는 부모 객체가 가진 프로퍼티 접근이나 메서드를 상속받아 호출하는 것이 가능하다.
- 함수 객체의 prototype 프로퍼티와 객체의 숨은 프로퍼티인 [[Prototype]] 링크를 구분해야 한다.
- 모든 객체는 자신을 생성한 생성자 함수의 prototype 프로퍼티가 가리키는 프로토타입 객체를 자신의 부모 객체로 설정하는 [[Prototype]] 링크로 연결한다.
- 생성된 객체의 실제 부모 역할을 하는 건 생성자 자신이 아닌 생성자의 prototype 프로퍼티가 가리키는 프로토타입 객체다.
4.5.2 객체 리터럴 방식으로 생성된 객체의 프로토타입 체이닝
- 자신의 부모 역할을 하는 프로토타입 객체의 프로퍼티 또한 마치 자신의 것처럼 접근하는 게 가능하다. 이것이 프로토타입 체이닝이다.
- 특정 객체의 프로퍼티나 메서드에 접근하려고 할 때, 해당 객체에 접근하려는 프로퍼티 또는 메서드가 없다면 [[Prototype]] 링크를 따라 자신의 부모 역할을 하는 프로토타입 객체의 프로퍼티를 차례대로 검색하는 것을 프로토타입 체이닝이라고 한다.
4.5.3 생성자 함수로 생성된 객체의 프로토타입 체이닝
- 자바스크립트에서 모든 객체는 자신을 생성한 생성자 함수의 prototype 프로퍼티가 가리키는 객체를 자신의 프로토타입 객체(부모 객체)로 취급한다.
4.5.4 프로토타입 체이닝의 종점
- Object.prototype 객체는 프로토타입 체이닝의 종점이다.
- 모든 자바스크립트 객체는 프로토타입 체이닝으로 Object.prototype 객체가 가진 프로퍼티와 메서드에 접근하고, 서로 공유가 가능하다.
4.5.5 기본 데이터 타입 확장
- 숫자, 문자열, 배열 등에서 사용되는 표준 메서드들의 경우, 이들의 프로토타입인 Number.prototype, String.prototype, Array.prototype 등에 정의되어 있다.
- 표준 빌트인 프로토타입 객체에도 사용자가 직접 정의한 메서드들을 추가하는 것을 허용한다.
4.5.6 프로토타입도 자바스크립트 객체다
- 프로토타입 객체에 동적으로 프로퍼티를 추가/삭제하는 것이 가능하다. 이렇게 변경된 프로퍼티는 실시간으로 프로토타입 체이닝에 반영된다.
4.5.7 프로토타입 메서드와 this 바인딩
- 메서드 호출 패턴에서의 this는 그 메서드를 호출한 객체에 바인딩 된다.
4.5.8 디폴트 프로토타입은 다른 객체로 변경이 가능하다.
- 해당 함수와 연결되는 디폴트 프로토타입 객체를 다른 일반 객체로 변경하는 것이 가능하다.
- 생성자 함수의 프로토타입 객체가 변경되면, 변경된 시점 이후에 생성된 객체들은 변경된 프로토타입 객체로 [[Prototype]] 링크를 연결한다는 것을 기억해야 한다.
- 변경되기 이전에 생성된 객체들은 기존 링크를 그대로 유지한다.
4.5.9 객체의 프로퍼티 읽기나 메서드를 실행할 때만 프로토타입 체이닝이 동작한다.
- 객체에 있는 특정 프로퍼티에 값을 쓰려고 한다면 프로토타입 체이닝이 동작하지 않는다. 그냥 그 객체에 프로퍼티가 수정/추가되는 것이다.
'JavaScript' 카테고리의 다른 글
[Vue] mixin 설명 (0) | 2020.03.03 |
---|---|
[React] React의 LifeCycle 정리 (0) | 2020.02.22 |
함수와 프로토타입 체이닝 (1) (0) | 2020.02.19 |
[You Don`t Know JS] Chapter 1. 타입, Chapter 2. 값 정리 (0) | 2020.02.13 |
JS 면접 문제 질문과 답변 (2) | 2018.08.27 |