- amplify
- AWS
- 캐시무효화
- S3
- javascirpt
- 프로그래머스
- nuxt
- Algorithm
- preload
- composition api
- 자바스크립트
- SSH
- IntersectionObserverAPI
- eslint
- html
- TypeScript
- JavaScript
- CF
- github
- programmers
- fetchpriority
- Prefetch
- 백준
- 모던자바스크립트DeepDive
우주선
모던 자바스크립트 Deep Dive ― (4) 본문
모던 자바스크립트 Deep Dive ― (4)
17장 생성자 함수에 의한 객체 생성
다양한 객체 생성 방식 중 생성자 함수를 사용하여 객체를 생성하는 방식을 살펴본다.
17.1 Object 생성자 함수
new 연산자와 함께 Object 생성자 함수를 호출한다.
생성자 함수란 new 연산자와 함께 호출하여 객체(인스턴스)를 생성하는 함수이다.
생성자 함수에 의해 생성된 객체는 인스턴스instance 라고 한다.
17.2 생성자 함수
생성자 함수에 의한 객체 생성 방식은 프로퍼티 구조가 동일한 객체 여러 개를 간편하게 생성할 수 있는 것이다.
new 연산자와 함께 호출하면 해당 함수는 생성자 함수로 동작한다.
function circle(radius){
//1
//2
this.radius = radius;
this.getDiameter = function(){ return 2*this.radius }
//3
}
const redCircle = circle(4)
( 여기서 this는 생성자 함수로서 호출했고, this는 생성자 함수가 미래에 생성할 인스턴스를 바인딩한다. )
생성자 함수의 인스턴스 생성 과정은 다음과 같다.
1. 암묵적으로 빈 객체(인스턴스)가 생성되고 this에 바인딩한다.
2. this에 바인딩되어 있는 인스턴스를 초기화한다.
3. 완성된 인스턴스가 바인딩된 this가 암묵적으로 반환된다.
명시적으로 다른 객체를 반환하면 명시된 객체가 반환되며, 명시적으로 원시 값을 반환하면 무시하고 this를 반환한다.
생성자 함수 내부에서 반환은 기본 동작이기 때문에 return문을 생략해야 한다.
함수는 객체이지만 일반 객체와는 달리 호출이 가능하다. 함수 객체는 일반 객체가 가진 내부 슬롯, 내부 메서드는 물론이고 함수로서 동작하기 위해 내부 메서드 [[call]]과 [[construct]]를 가지고 있다.
- [[call]] : 일반 함수로서 호출.
- [[construct]] : 생성자 함수로서 호출. 생성자 함수로서 호출할 수 없으면 [[construnct]]를 갖지 않으며 non-constructor 함수라고 한다.
위에 따라 함수는 다음과 같이 나눌 수 있다.
- constructor 함수 : 생성자 함수로서 호출할 수 있다. 함수 선언문, 함수 표현식, 클래스
- non-constructor 함수 : 메서드(ES6 메서드 축약표현), 화살표 함수
new 연산자와 쓸 수 있는 함수는 constructor 함수여야 한다.
생성자 함수는 일반적으로 첫 문자를 대문자로 기술하는 파스칼 케이스로 명명하는 컨벤션을 추천한다.
생성자 함수로서 호출되었으면 함수 내부의 new.target은 자신을 가르키고, 일반 함수로서 호출되었으면 new.target은 undefined이다.
18장 함수와 일급 객체
18.1 일급 객체
다음과 같은 조건을 만족하는 객체는 일급 객체이다. 자바스크립트의 함수는 일급 객체이다.
- 무명의 리터럴로 생성 가능하다.
- 변수나 자료구조에 저장할 수 있다.
- 함수의 매개변수에 전달할 수 있다.
- 함수의 반환값으로 사용할 수 있다.
함수와 일반 객체의 차이점은 함수 객체는 호출할 수 있으며, 함수 객체에는 일반 객체에는 없는 함수 고유의 프로퍼티를 소유한다는 것이다.
18.2 함수 객체의 프로퍼티
1) arguments 프로퍼티
arguments 프로퍼티 값은 arguments 객체이다.
함수 호출 시 전달된 인수들의 정보를 담고 있는 순회 가능한iterable 유사 배열 객체이며 함수 내부에서 지역 변수처럼 사용된다.
배열 형태로 인자 정보를 담고 있지만 유사 배열 객체로, for문으로 순회할 수 있다.
배열 메서드는 그대로 사용할 수 없어 Function.prototype.call 을 사용해야 한다. -> 번거로워서 Rest 파라미터가 도입되었다.
실제로 내가 자주 쓰는 Rest 파라미터는 spread문법이라고도 불리는 ...args 와 같이 점 3개를 앞에 붙이는 것이다.
2) caller 프로퍼티
3) length 프로퍼티 : 함수 객체의 ㅣength 프로퍼티는 함수를 정의할 때 선언한 매개변수의 개수이다.
4) name 프로퍼티 : ES6에서 표준으로 들어오며 ES6부터 익명 함수의 경우에도 함수 객체를 가리키는 식별자를 값으로 갖는다.
5) __proto__ 접근자 프로퍼티
모든 객체는 [[prototype]] 이라는 내부 슬롯을 갖는다. __proto__ 프로퍼티는 [[prototype]]내부 슬롯이 가리키는 프로토타입 객체에 접근하기 위해 사용하는 접근자 프로퍼티다.
5) prototype 프로퍼티
생성자 함수로 호출할 수 있는 객체인 constructor 함수만이 소유하는 프로퍼티다.
함수가 생성자 함수로 호출될 때 생성할 인스턴스의 프로토타입 객체를 가리킨다.
19장 프로토타입
자바스크립트는 객체지향 프로그래밍 능력을 지니고 있는 프로토타입 기반의 객체지향 프로그래밍 언어다. 자바스크립트를 이루는 거의 모든 것(원시 값 제외)이 객체이기 때문이다.
객체는 상태 데이터와 동작을 하나의 논리적 단위로 묶은 복합적인 자료구조다. 상태를 프로퍼티, 동적을 메서드라고 부른다.
각 객체는 고유의 기능을 갖는 독립적인 부품이지만 다른 객체와 관계성을 갖는다. 다른 객체의 상태 데이터나 동작을 상속받아 사용하기도 한다.
19.2 상속과 프로토타입
상속은 어떤 객체의 프로퍼티 또는 메서드를 다른 객체가 상속받아 그대로 사용할 수 있는 것을 말한다.
프로토타입을 기반으로 상속을 구현하여 불필요한 중복을 제거한다.
//생성자 함수
function Circle(){
this.radius = radius
}
//circle생성자 함수가 생성한 모든 인스턴스가 상속할 수 있도록 프로토타입 추가
Circle.prototpe.getArea = function(){
return Math.PI * this.radius ** 2
}
//인스턴스 생성
const circle1 = new Circle(1)
const circle2 = new Circle(2)
//메서드 공유(호출 가능!)
console.log(circle1.getArea===circle2.getArea)
19.3 프로토타입 객체
프로토타입은 어떤 객체의 상위 객체의 역할을 하는 객체로서 다른 객체에 공유 프로퍼티를 제공한다. 하위 객체는 상위 객체의 프로퍼티를 자유롭게 사용한다.
모든 객체는 [[prototype]] 이라는 내부 슬롯을 가지며 이 내부 슬롯의 값은 프로토타입의 참조다.
모든 객체는 __proto__ 접근자 프로퍼티를 통해 자신의 프로토타입인 [[prototype]] 내부슬롯에 간접적으로 접근할 수 있다.
왜 간접적으로 접근하냐면 상호 참조에 의해 프로토타입 체인이 생성되는 것을 방지하기 위해서이다.
프로토타입 체인은 단방향 링크드 리스트(하위 객체에서부터 상위 객체로 검색)로 구현되어야 하기 때문이다.
함수 객체만이 소유하는 prototype 프로퍼티는 생성자 함수가 생성할 인스턴스의 프로로타입을 가리킨다.
non-constructor인 화살표 함수와 ES6 메서드 축약표현으로는 prototype 프로퍼티를 소유하지 않는다.
모든 객체가 가지고 있는 __proto__ 접근자 프로퍼티와 함수 객체만이 가지고 있는 prototype 프로퍼티는 결국 동일한 프로토타입을 가리킨다! 위의 Circle 을 예로 들면 Circle.prototype === circle1.__proto__ 는 true 이다.
19.4 리터럴 표기법에 의해 생성된 객체의 생성자 함수와 프로토타입
그렇다면 객체 리터럴과 같은 let abc=[1,2,3] 은 어떨까 ?
추정 연산을 통해 let abc = new Array(1,2,3)과 거의 같은 동작을 행하는데(책에서 서술하길 본질적인 면에서 큰 차이가 없다 함) 여기서 Array라는 생성자 함수의 prototype에 sort()라던가 length 등이 있어서 우리는 abc.sort(), abc.length 를 사용할 수 있는 것이다.
mdn에서 메서드를 찾아보면 Array.prototype.map 이 있는데 여기의 prototype이 Array의 prototype이라는 것이다.
리터럴 표기법에 의해 생성된 객체도 상속을 위해 프로토타입이 필요하며, 프로토타입과 생성자 함수는 단독으로 존재할 수 없고 쌍으로 존재한다.
19.5 프로토타입의 생성 시점
프로토타입은 생성자 함수가 생성되는 시점에 더불어 생성된다.
non-constructor는 프로토타입이 생성되지 않는다.
호이스팅에 따라 생성자 함수는 어떤 코드보다 먼저 평가되어 함수 객체가 되는데, 이때 프로토타입도 더불어 생성된다.
그렇다면 표준 빌트인 객체는 어떨까?
Object, String, Number, RegExp , Promise 등과 같은 빌트인 생성자 함수도 빌트인 생성자 함수가 생성되는 시점에 프로토타입이 생성된다. 빌트인 객체는 전역 객체의 프로퍼티이기 때문에 브라우저 환경에서 전역 객체(window)가 생성되는 시점에 생성된다.
window.Object === Object // true
19.6 객체 생성 방식과 프로토타입의 결정
객체 생성 방식은 다양하다.
1) 객체 리터럴 : Object.prototype을 프로토타입으로 갖게 되며 상속받는다.
2) Object 생성자 함수 : Object.prototype을 프로토타입으로 갖게 되며 상속받는다.
3) 생성자 함수 : 생성자 함수에 의해 생성되는 객체의 프로토타입은 생성자 함수의 prototype 프로퍼티에 바인딩되어있는 객체다.
19.7 프로토타입 체인
프로토타입 체인은 상속과 프로퍼티 검색을 위한 메커니즘이다.
(이전 스코프에서 스코프 체인은 식별자 검색을 위한 메커니즘인 것과 차이가 있다.)
하위 객체에서 상위 객체로 검색하며 Object.prototype을 프로토타입 체인의 종점이라 한다.
19.8 오버라이딩과 섀도잉
오버라이딩 : 상위 클래스가 가진 메서드를 하위 클래스가 재정의하여 사용
오버라이딩하여 상속 관계에 의해 프로퍼티가 가려지는 현상을 프로퍼티 섀도잉이라 한다.
하위 객체를 통해 프로토타입의 프로퍼티를 변경, 삭제하는 것은 불가능하다. 즉 get 엑세스는 허용되나 set은 불허한다.
19.9 프로토타입의 교체
교체할 수 있으나 교체 시 야기되는 여러 문제들 때문에 교체하지 않는 것이 좋다. 클래스를 사용하라.
19.10 instanceof 연산자
생성자 함수의 prototype에 바인딩 된 객체가 프로토타입 체인 상에 존재하는지 확인한다.
객체 instanceof 생성자 함수 // true or false 로 평가 ( 우변이 함수가 아니면 타입에러 )
19.11 직접 상속
Object.create 메서드로 프로토타입을 지정하여 새로운 객체를 생성한다. 추정 연산을 호출한다.
Object.create는 Object 함수의 정적 메서드다.
19.12 정적 프로퍼티/메서드
생성자 함수로 인스턴스를 생성하지 않아도 참조/호출할 수 있는 프로퍼티/메서드이다.
정적 메서드의 경우 Object.keys() 와 같이 구분하고
프로토타입 메서드의 경우 Obejct.prototype.hasOwnProtperty() 와 같이 표기한다.
19.13 프로퍼티 존재 확인
1) in 연산자
19.14 프로퍼티 열거
1) for ... in 문 : 객체의 모든 프로퍼티를 순회하며 열거한다. 모든 객체의 프로토타입 체인 상에 존재하는 모든 프로토타입의 프로퍼티 중에서 프로퍼티 어트리뷰트 [[Enumerable]] 값이 true인, 열거 가능한 값만을 열거한다. 키가 심벌인 프로퍼티는 제외한다.
2) Object.keys : 프로퍼티 키를 열거
3) Object.value : 프로퍼티 값을 열거
4) Object.entries : 프로퍼티 키와 값을 배열에 담아 열거
'JavaScript' 카테고리의 다른 글
Intersection Observer API (0) | 2022.10.21 |
---|---|
모던 자바스크립트 Deep Dive ― (5) (1) | 2022.10.05 |
모던 자바스크립트 Deep Dive ― (3) (0) | 2022.09.21 |
모던 자바스크립트 Deep Dive ― (2) (0) | 2022.09.14 |
모던 자바스크립트 Deep Dive ― (1) (0) | 2022.09.07 |