독립적인 객체의 집합으로 프로그램을 표현하려는 프로그래밍 패러다임
객체 : 상태를 나타내는 데이터(데이터 프로퍼티)와, 상태를 조작할 수 있는 동작(메서드)을 하나의 단위로 묶은 자료구조
일반적인 생성자 함수로 여러 객체를 만들면 동일한 메서드가 계속 만들어짐
function Person(name){
this.name = name;
this.hi = function(){
console.log(`hi i'm ${this.name}`);
};
}
const person1 = new Person('John');
const person2 = new Person('AJ');
person1.hi===person2.hi //false
이를 프로토타입 기반으로 하면 해결 가능
생성자 함수에 의해 만들어진 인스턴스는 생성자 함수의 프로토타입의 모든 프로퍼티와 메서드를 상속받는다
function Person(name){
this.name = name;
}
Person.prototype.hi = function(){
console.log(`hi i'm ${this.name}`);
};
const person1 = new Person('John');
const person2 = new Person('AJ');
person1.hi===person2.hi //true
모든 객체는 [[Prototype]] 내부 슬롯을 갖고 [[Prototype]]의 값은 프로토타입 객체의 참조이다
[[Prototype]] 에 저장되는 프로토타입 객체는 객체 생성 방식에 의해 결정
객체 생성 방식에 따라 프로토타입이 결정되고 [[Prototype]]에 저장
객체 리터럴에 의해 생성된 객체 : Object.prototype
생성자 함수에 의해 생성된 객체 : 생성자함수의 prototype
객체, 프로토타입, 생성자 함수는 서로 연결되어 접근 가능
객체는 _ proto _ 접근자 프로퍼티로 프로토타입에 간접 접근 가능
프로토타입은 자신의 constructor프로퍼티로 생성자 함수에 접근
생성자함수는 자신의 prototype프로퍼티로 프로토타입에 접근
모든 객체는 _ proto _ 로 자신의 프로토타입에 간접 접근 가능
객체가 직접 갖고 있는 것은 아니고 Object.protype의 프로퍼티인데 상속받아 사용
직접 상속을 통해 Object.prototype을 상속 받지 않는 객체는 _ proto _ 못씀
프로토 타입의 참조를 원하면 다르게
const obj = {};
const parent = {x:1};
obj.__proto__ = parent; //값을 할당 했으니 setter함수 실행
obj.x; // 1
Object.getPrototypeOf(obj); // obj.__proto__ 와 같음
Object.setPrototypeOf(obj,parent);
constructor의 prototype프로퍼티는 생성자 함수가 생성할 인스턴스의 프로토타입을 가르킴

function Person(name){
this.name = name;
}
const me = new Person('AJ');
Person.prototype === me.__proto__ //true
Person.prototype.constructor === Person //true
Object.getPrototypeOf(me).constructor == Person //true
객체 리터럴에 의해 생성한 객체도 Object 생성자 함수와 constructor로 연결되있다
{리터럴로만든객체}.constructor ===Object //true 이지만 Object가 이 객체를 만든건 아님
함수의 경우 Function 생성자로 만들면 렉시컬스코프,클로저가 안만들어지는데
일반적인 함수 선언문으로 만든 함수의 constructor는 Function 생성자를 가르킴
리터럴 표기법으로 만든 객체도 프로토타입이 필요하기 때문에 가상적인 생성자 함수를 갖는다
프로토타입과 생성자 함수는 항상 쌍으로 존재
프로토타입은 생성자 함수가 생성되는 그 시점에 같이 생성됨
함수가 평가되어 함수 객체를 생성하는 시점에 프로토타입도 같이 생성됨
함수 선언문은 런타임 이전에 실행되므로 이 때 함수 객체와 프로토타입이 만들어진다
생성된 프로토타입도 객체이므로 프로토타입이 있다
생송된 프로토타입의 프로토타입은 Object.prototype
모든 빌트인 생성자 함수는 전역 객체가 생성되는 시점에 생성됨
이 때 빌트인 생성자 함수의 프로토타입이 생성
객체가 생성되기 이전에 생성자 함수와 프로토타입은 이미 객체화되어 존재함
생성자 함수나 리터럴로 객체를 생성하면 이 때 생성된 객체의 [[Prototype]]에 할당된다
이로써 새롭게 만들어진 객체는 프로토타입을 상속받는다
객체는 여러가지 방법으로 만들 수 있다
모든 방식은 결국 추상 연산 OrdinaryObjectCreate에 의해 객체를 생성
OrdinaryObjectCreate는 생성할 객체의 프로토타입을 인수로 무조건 받음
빈 객체를 생성 후 그 객체의 [[Prototype]]에 전달받은 인수를 할당
객체 생성 방식에 따라 다른 인수로 다른 프로토타입을 넘김
객체 리터럴을 평가하여 객체를 생성할 때 Object.prototype이 인수로 전달
즉 객체 리터럴로 생성한 객체는 Object.prototype이 자신의 프로토타입이기 때문에 Object.prototype의 모든 프로퍼티와 메서드를 상속받아 사용 가능
추상 연산 OrdinaryObjectCreate에 Object.prototype이 전달
객체 리터럴과 같다
추상 연산 OrdinaryObjectCreate에 생성자 함수의 prototype에 바인딩된 객체를 전달

사용자 정의 생성자 함수와 함께 생성된 프로토타입은 프로퍼티로 constructor밖에 없다.
하지만 Person.prototype의 prototype이 Object.prototype이기 때문에 여러 메서드 사용이 가능한 것
객체의 프로퍼티에 접근할 때 해당 객체에 그 프로퍼티가 없으면 [[Prototype]] 내부 슬롯 참조를 따라 프로토타입의 프로퍼티를 순차적으로 검색
이런 프로토타입 체인은 자바스크립트가 객체지향 프로그래밍의 상속을 구현하는 메커니즘이다
이 프로토타입 체인의 종점은 Object.prototype이다
Object.prototype의 [[Prototype]] 은 null
객체가 갖고있지 않은 프로퍼티여도 에러가 나지 않고 undefined 반환
프로토타입 체인은 상속과 프로퍼티 검색을 위한 메커니즘이다
생성자 함수로 생성한 인스턴스 객체에 프로토타입이 갖고있는 프로퍼티와 동일한 이름의 프로퍼티를 추가하면 그 인스턴스 프로퍼티가 프로토타입의 프로퍼티를 가려버림 = 프로퍼티 섀도잉
하위 객체를 통해 상위의 프로토타입의 프로퍼티 변경,삭제는 불가

me.sayHello() 는 인스턴스에 새롭게 추가한 인스턴스 프로퍼티가 실행됨
const Person = (function(){
function Person(name){
this.name = name;
}
Person.prototype = {
// constructor : Person, 연결을 해줘야함
say(){
console.log('hi');
}
};
return Person;
}());
const me = new Person('AJ');

프로토타입을 교체하면 생성자 함수와 constructor의 연결이 끊김
const parent = {
say(){
console.log('hi');
}
};
Object.setPrototypeOf(me,parent);
새롭게 설정한 프로토타입에 constructor가 없어서 생성자 함수와의 연결이 끊어짐

여기서는 Person.prototype이 새로운 프로토타입을 안가르킴
객체 instanceof 생성자 함수
객체의 프로토타입 체인 상에 생성자 함수의 prototype에 바인딩된 객체가 존재하면 true
앞에서 인스턴스에 의해 프로토타입을 교체하면 생성자함수의 prototype 프로퍼티가 교체된 프로토타입 객체를 가르키지 않으므로 false
생성자 함수에 의한 교체는 연결이 안끊어져서 새롭게 프로토타입을 교체해도 true
첫번째 인수로 프로토타입으로 지정할 객체를 전달해준다
let obj = Object.create(null); // Object.prototype의 메서드 사용 불가
obj = Object.create(Object.prototype);
// obi={x:1};과 동일
obj = Object.create(Object.prototype,
{
x: { value: 1, writable: true, enumerable: true, configurable: true }
});
Object.prototype 메서드는 간접 호출하는 것이 좋다
const Proto={x:10};
const obj = {
y = 10,
__proto__ : Proto
};
생성자 함수 자체가 갖는 프로퍼티,메서드
인스턴스 생성없이 호출이 가능
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function () {
console.log( Hi! My name is ${this.name} );
}
// 정적 프로퍼티
Person.staticProp = 'static prop';
//정적 메서드
Person.staticMethod = function () {
console.log('staticMethod');
J;
const me = new Person ('Lee' );
Person.staticMethod(); // 인스턴스 없이 바로 호출 가능
me.staticMethod(); // TypeError: me.staticMethod is not a function

인스턴스의 프로토타입 체인에 정적 메서드는 없기 때문에 당연히 호출이 불가
객체에 프로퍼티가 있나 없나
해당 객체의 프로토타입 체인을 다 검색
직접적인 프로퍼티가 아니라 상속받은 거여도 true 나옴
const person = {
name : 'aj',
age : 20
};
'name' in person; // true
'height' in person; // false
'hasOwnProperty' in person; // true
Reflect.has(person,'name'); //true ES6
해당 객체 고유의 프로퍼티일때만 true
상속받은 프로퍼티면 false
person.hasOwnProperty('hasOwnProperty'); // false
person.hasOwnProperty('age'); // true
해당 객체의 프로토타입 체인에 존재하는 모든 프로퍼티중 [[Enumerable]]이 true인 프로퍼티의 키를 열거
프로퍼티 키가 심벌인 프로퍼티는 제외
상속받은 프로퍼티가 아닌 고유의 프로퍼티인지 따질려면 hasOwnproperty해줘야
const person = {
name : 'aj',
age : 20
};
for(const key in person){
console.log(key); //name,age
}
배열의 성분에 접근할 때 for ... in 을 사용하면,
배열도 객체기 때문에 프로퍼티를 갖을 수 있는데 얘가 포함된다
배열 내장 함수 다 튀어나옴
for ... in 쓰지말길
const arr = [1,2,3,4];
arr.x = 5;
for (const i in arr){
console.log(arr[i]); // 1 2 3 4 5
}
const person = {
name : 'aj',
age : 20
};
Object.keys(person); // ['name','age']
Object.values(person); // ['aj',20]
Object.entries(person); // [['name','aj'],['age',20]]