이안의 평일코딩

19-2장 프로토타입 본문

Study/JS Diver

19-2장 프로토타입

이안92 2021. 7. 6. 13:21
반응형

 

p.280

- 객체의 생성 방법은 객체 리터럴, Object 생성자 함수, 생성자 함수, Object.create 메서드, 클래스(ES6)가 있다.

- 프로토타입은 추상 연산 OrdinaryObjectCreate에 전달되는 인수에 의해 결정된다. 이 인수는 객체가 생성되는 시점에 객체 생성 방식에 의해 결정된다.

 

* 객체 리터럴에 의해 생성된 객체의 프로토타입

- 객체 리터럴에 의해 생성된 객체의 프로토타입은 추상 연산 OrdinaryObjectCreate에 전달되는 프로토타입은 Object.prototype다. 즉 객체 리터럴에 의해 생성되는 객체의 프로토타입은 Object.prototype이다.

 

p.281

객체 리터럴이 평가되면 객체는 constructor 프로퍼티와 hasOwnProperty 메서드 등을 소유하지 않지만 상속을 통해 자신인의 자산인 것처럼 자유롭게 사용할 수 있다.

const obj = { x: 1 };

// 객체 리터럴에 의해 생성된 obj 객체는 Object.prototype을 상속받는다.
console.log(obj.constructor === Object);  // true
console.log(obj.hasOwnProperty('x'));     // true

 

* Object 생성자 함수에 의해 생성된 객체의 프로토타입

- Object 생성자 함수를 인수 없이 호출하면 빈 객체가 생성된다. Object 생성자 함수를 호출하면 객체 리터럴과 마찬가지로 추상 연산 OrdinaryObjectCreate가 호출된다. 프로토타입 또한 Object.prototype.

const obj = new Object();
obj.x = 1;

// Object 생성자 함수에 의해 생성된 obj 객체는 Object.prototype을 상속받는다.
console.log(obj.constructor === Object);  // true
console.log(obj.hasOwnProperty('x'));     // true

 

p.283

- 객체 리터럴과 Object 생성자 함수에 의한 객체 생성 방식의 차이는 프로퍼틸르 추가하는 방식에 있다. 객체 리터럴 방식은 객체 리터럴 내부에 프로퍼티를 추가하지만 Object 생성자 함수 방식은 일단 빈 객체를 생성한 이후 프로퍼티를 추가해야 한다.

 

* 생성자 함수에 의해 생성된 객체의 프로토타입

- new 연산자와 함께 생성자 함수를 호출하여 인스턴스를 생성하면 다른 객체 생성 방식과 마찬가지로 추상 연산 OrdinaryObjectCreate가 호출된다. 생성자 함수에 의해 생성되는 객체의 프로토타입은 생성자 함수의 prototype 프로퍼티에 바인딩되어 있는 객체다.

function Person(name) {
  this.name = name;
}

// 프로토타입 메서드 (상속)
Person.prototype.sayHello = function () {
  console.log(`Hi! My name is ${this.name}`);
};

const me = new Person('Lee');

me.sayHello(); // Hi! My name is Lee

- 표준 빌트인 객체인 Object 생성자 함수와 더불어 생성된 프로토타입 Object.prototype은 다양한 빌트인 메서드를 가지고 있지만 사용자 정의 생성자 함수와 생성된 프로토타입 Person.prototype의 프로퍼티는 constructor뿐이다.

 

p.285

- 프로토타입의 프로토타입은 언제나 Object.prototype이다. 위의 예제에서 Person 생성자 함수에 의해 생성된 me 객체는 Object.prototype의 메서드도 호출할 수 있는데 이것은 me 객체가 Person.prototype뿐만 아니라 Object.prototype도 상속받았다는 것을 의미한다.

Object.getPrototypeOf(me) === Person.prototype; // true
Object.getPrototypeOf(Person.prototype) === Object.prototype; // true

p.286

- 내부 슬롯의 참조에 따라 자신의 부모 역할을 하는 프로토타입의 프로퍼티를 순차적으로 검색하는데 이를 프로토타입 체인이라 한다. 프로토타입 체인은 자바스크립트가 객체지향 프로그래밍의 상속을 구현하는 메커니즘이다.

 

p.287

- 프로토타입 체인은 상속과 프로퍼티 검색을 위한 메커니즘이고 스코프 체인은 식별자 검색을 위한 메커니즘이다.

 

p.296

- instanceof 연산자는 이항 연산자로서 좌변에 객체를 가리키는 식별자, 우변에 생성자 함수를 가리키는 식별자를 피연산자로 받는다. 만약 우변의 피연산자가 함수가 아닌 경우 TypeError가 발생한다.

객체 instanceof 생성자 함수

 

- 우변의 생성자 함수의 prototype에 바인딩된 객체가 좌변의 객체의 프로토타입 체인 상에 존재하면 true로 평가되고, 그렇지 않은 경우에는 false로 평가된다.

 

// 생성자 함수
function Person(name) {
  this.name = name;
}
const me = new Person('Lee');

// Person.prototype이 me 객체의 프로토타입 체인 상에 존재함
console.log(me instanceof Person); // true
// Object.prototype이 me 객체의 프로토타입 체인 상에 존재함
console.log(me instanceof Object); // true

// 프로토타입으로 교체할 객체
const parent = {};

// 프로토타입의 교체
Object.setPrototypeOf(me, parent);

// Person.prototype이 me 객체의 프로토타입 체인 상에 존재하지 않음
console.log(me instanceof Person); // false
// Object.prototype이 me 객체의 프로토타입 체인 상에 존재함
console.log(me instanceof Object); // true

// parent 객체를 Person 생성자 함수의 prototype 프로퍼티에 바인딩한다
Person.prototype = parent;

// Person.prototype이 me 객체의 프로토타입 체인 상에 존재함
console.log(me instanceof Person); // true
// Object.prototype이 me 객체의 프로토타입 체인 상에 존재함
console.log(me instanceof Object); // true

p.297

- Person.prototype이 me 객체의 프로토타입 체인 상에 존재하지 않으면 false로 평가되고 프로토타입으로 교체한 parent 객체를 Person 생성자 함수의 prototype 프로퍼티에 바인딩하면 me instanceof Person은 true로 평가된다.

 

p.301

- Object.create 메서드는 첫 번째 매개변수에 전달한 객체의 프로토타입 체인에 속하는 객체를 생성한다. 즉, 객체를 생성하면서 직접적으로 상속을 구현하는 것이다.

 

p.306

- 객체에 특정 프로퍼티가 존재하는지 확인하기 위해 in 연산자(ES6에서 도입된 Reflect.has메서드) 또는 Object.prototype.hasOwnProperty 메서드를 사용하면 된다.

const person = {
  name: 'Lee',
  address: 'Seoul'
};

console.log('name' in person); // true
console.log('age' in person);  // false

console.log(Reflect.has(person, 'name'));   // true
console.log(person.hasOwnProperty('name')); // true

 

- in 연산자는 person 객체가 속한 프로토타입 체인 상에 존재하는 모든 프로토타입에서 검색하고 Object.prototype.hasOwnProperty 메서드는 인수로 전달받은 프로퍼티 키가 객체 고유의 프로퍼티 키인 경우에만 true를 반환하고 상속받은 프로토타입의 프로퍼티 키인 경우 false를 반환한다.

console.log('toString' in person); // true
console.log(person.hasOwnProperty('toString')); // false

 

p.307

- 객체의 모든 프로퍼티를 순회하며 열거(enumeration)하려면 for...in 문을 사용한다.

const person = {
  name: 'Lee',
  address: 'Seoul'
};

for (const key in person) {
  console.log(key + ': ' + person[key]);
}

// name: Lee
// address: Seoul

 

p.308

- for ... in문은 in 연산자처럼 순회 대상 객체의 프로퍼티뿐만 아니라 상속받은 프로토타입의 프로퍼티까지 열거하지만 toString과 같은 Object.prototype의 프로퍼티는 열거되지 않는다. prototype.string 프로퍼티의 프로퍼티 어트리뷰트 [[Enumerable]]의 값이 false이기 때문이다. 프로퍼티 어트리뷰트 [[Enumerable]]은 프로퍼티의 열거 가능 여부를 나타내며 불리언 값을 갖는다. 즉, for ... in 문은 객체의 프로토타입 체인 상에 존재하는 모든 프로토타입의 프로퍼티 중에서 프로퍼티 어트리뷰트 [[Enumerable]]의 값이 true인 프로퍼틸르 순회하며 열거(enumeration)한다.

 

p.311

- 객체 자신의 고유 프로퍼티만 열거하기 위해서는 for ... in 문을 사용하는 것보다 Object.keys/values/entries 메서드를 사용하는 것을 권장한다. 

const person = {
  name = 'Lee',
  address: 'Seoul',
  __proto__: { age: 20 }
};

console.log(Object.keys(person)); // ["name", "address"]
console.log(Object.values(person)); // ["Lee", "Seoul"]
console.log(Object.entries(person)); // [["name", "Lee"], ["address", "Seoul"]]
Object.entries(person).forEach(([key, value]) => console.log(key, value));
/*
name Lee
address Seoul
*/

 

p.312

- Object.keys 메서드는 객체 자신의 열거 가능한(enumberable) 프로퍼티 키를 배열로 반환한다. ES8에서 도입된 Object.values 메서드는 객체 자신의 열거 가능한 프로퍼티 값을 배열로 반환하고 Object.entries 메서드는 객체 자신의 열거 가능한 프로퍼티 키와 값의 쌍의 배열을 배열에 담아 반환한다.

반응형
Comments