모든 객체는 proto접근자 프로퍼티 를 통해 자신의 프로토타입
[Prototype] 내부 슬롯에 간접적으로 접근 가능
__prototype__
은 접근자 프로퍼티이다.
__proto__
는 접근자 프로터피이며, 간접적으로 접근할 수 있는 수단을 제고
__proto__
가 접근자 프로퍼티이므로, getter/setter 접근자 함수를 통해 프로토타입 취득 및 할당 가능
const obj = {};
const parent = {x:1};
// proto 접근자 프로퍼티의 getter 접근자 함수로 obj 객체의 프로토타입 객체 취득
console.log(obj.__proto__);
// [Object: null prototype] {}
obj.__proto__ = parent;
// setter 접근자 함수로 obj 객체의 프로로타입에 값 할당.
__proto__
접근자 프로퍼티를 통해 프로토타입에 접근
단방향 연결 리스트로 구현
되어야 함.const obj = {};
// obj 객체의 생성자 함수는 Object 생성자 함수다.
console.log(obj.constructor === Object); // true
프로토타입은 생성자 함수가 생성되는 시점에 더불어 생성된다.
생성자 함수에는
함수 정의가 평가되어 함수 객체를 생성하는 시점에 프로토타입도 더불어 생성된다.
//함수 정의가 평가되어 함수 객체를 생성하는 시점에 프로토타입 더불어 생성
//함수 호이스팅 적용
console.log(Person.prototype); // {constructor : f}
function Person(name){
this.name = name;
}
생성된 프로토타입은 constructor 프로퍼티만을 갖는 객체이다.
프로토타입도 객체이다. (모든 객체는 프로토타입을 갖는다)
생성된 프로토타입의 프로토타입은 Object.prototype
빌트인 생성자 함수는
빌트인 생성자 함수가 생성되는 시점
에 프로토타입 생성된다.
모든 빌트인 함수는 전역 객체가 생성되는 시점에 생성된다.
생성된 프로토타입은 빌트인 생성자 함수의 prototype 프로퍼티에 바인딩
객체 리터럴
Object 생성자 함수
생성자 함수
Object.create 메소드
클래스 (ES6)
OrdinaryObjectCreate 호출로 -> 빈 객체를 생성
객체에 추가할 프로퍼티 목록이 인수로 전달될 경우 -> 프로퍼티를 객체에 추가
Object.prototype
이다.const obj = {x:1}; // 객체 리터럴로 생성된 obj 객체
1. obj객체에는 (constructor/hasOwnProperty) 소유x
2. 사용 가능 이유 -> Object.prototype에 있는 프로퍼티 상속 받았기 때문
console.log(obj.constructor === Object); // true
console.log(obj.hasOwnProperty("x")); // true
Object 생성자 함수에 의해 생성되는 객체의 프로토타입은
Object.prototype
const obj = new Object();
obj.x = 1;
console.log(obj.constructor === Object); // true
console.log(obj.hasOwnProperty("x")); // true
생성자 함수에 의해 생성되는 객체의 프로토타입은 생성자 함수의 prototype 프로퍼티에 바인딩 되어 있는 객체
// 사용자 정의 생성자 함수
function Person(name) {
this.name = name;
}
// Person.prototype 에 프로퍼티를 동적으로 추가/삭제 가능
Person.prototype.sayHello = function () {
console.log(`Hi! My name is ${this.name}`);
};
// 사용자 정의 생성자 함수로 생성된 인스턴스
const me = new Person("WI");
const you = new Person("KIM");
me.sayHello(); // Hi! My name is WI
you.sayHello(); // Hi! My name is KIM
console.log(me.constructor === Person); // true
console.log(you.constructor === Person); // true
Object.prototype
이다.자바스크립트는 -> 객체의 프로퍼티(메소드 포함)에 접근하려고 할 때 해당 객체에 접근하려는 프로퍼티가 있는지 확인한다.
없다면 -> [[prototype]] 내부 슬롯의 참조값을 따라
이런 일련의 과정을 프로토타입 체인이라고 한다.
function Person(name) {
this.name = name;
}
const me = new Person("WI");
console.log(me.hasOwnProperty("name")); // true
// 1. hasOwnProperty 메서드가 me 객체에 프로퍼티에 존재하는지 검색한다.
// 2. 없기 때문에, me 객체의 [[Prototype]] 내부 슬롯의 참조값을 통해, Person.prototype 객체의 프로퍼티를 검색
// 3. Person.prototype 에도 hasOwnProperty 메서드가 없으므로, [[Prototype]] 내부 슬롯의 참조값을 통해 Object.prototype 프로퍼티를 검색
// 4. Object.prototype 에는 hasOwnProperty 메서드가 있으므로, 자바스크립트 엔진은 Object.prototype.hasOwnProperty 메서드를 호출
// (이 때 this 에는 me 객체가 바인딩된다.)
모든 객체는 Object.prototype를 상속 받는다.
Object.prototype
를 프로토타입 체인의 종점 이라 한다.Object.prototype
의 프로토타입은 없다 --> null이다.Object.prototype
에도 없는 프로퍼티를 조회할 경우, undefined 를 반환프토로타입 체인
상속과 프로퍼티 검색을 위한 메커니즘
이다.스코프 체인
스코프 체인은 식별자 검색을 위한 메커니즘
스코프 체인과 프로토타입 체인은 서로 관련없이 별도로 동작하는게 아니라, 서로 협력하여 식별자와 프로퍼티를 검색하는데 사용한다.
우변의 생성자 함수의 prototype에 바인딩된 객체가
-> 좌변의 객체의 프로토타입 체인 상에 존재하는지 체크한다.
function Person(name){
this.name = name;
}
const me = new Person("WI");
const parent = {};
Object.setPrototypeOf(me,parent);
// Person 생성자 함수와 parent 객체는 연결되어 있지 않다.
console.log(Person.prototype === parent); // false
console.log(parent.constructor === Person); // false
// parent 객체를 Person 생성자 함수의 prototype 프로퍼티에 바인딩
Person.prototype = parent;
// Person.prototype 이 me 객체의 프로토타입 체인 상에 존재함
console.log(me instanceof Person); // true
// Object.prototype 이 me 객체의 프로토타입 체인 상에 존재함
console.log(me instanceof Object); // true
명시적으로 프로토타입을 지정하여 새로운 객체를 생성
let obj = Object.create(null);
console.log(Object.getPrototypeOf(obj) === null); // true
//obj -> Object.prototype -> null
obj = Object.create(Object.prototype);
console.log(Object.getPrototypeOf(obj) === Object.prototype); // true
obj = Object.create(Object.prototype, {
x : { value: 1, writable: true, enumerable: true, configurable: true }
});
console.log(Object.getPrototypeOf(obj) === Object.prototype); // true
const myProto = { x: 10 };
// obj -> myProto -> Object.prototype -> null
obj = Object.create(myProto);
console.log(Object.getPrototypeOf(obj) === myProto); // true
function Person(name) {
this.name = name;
}
// obj -> Perosn.prototype -> Object.prototype -> null
obj = Object.create(Person.prototype);
console.log(Object.getPrototypeOf(obj) === Person.prototype); // true
const myProto = {x:10};
// 객체 리터럴에 의해 객체를 생성하면서, 프로토타입을 지정하여 직접 상속을 구현할 수 있다.
const obj = {
y : 20,
__proto__ : myProto,
};
위 obj 정의는 다음과 같다.
const obj = Object.create(myProto, {
y: { value: 20, writable: true, enumerable: true, configurable: true }
})
*/
console.log(obj.x, obj.y); // 10 20
console.log(Object.getPrototypeOf(obj) === myProto); // true
생성자 함수로 인스턴스를 생성하지 않아도 참조/호출 가능한 프로퍼티/메소드
생성자 함수도 객체이다.
생성자 함수도 프로퍼티나 메소드를 소유할 수 있다.
생성자 함수가 소유한 프로퍼티나 메소드를 정적 프로퍼티 / 메소드라고 한다.
// 생성자 함수
function Person(name) {
this.name = name;
}
// 프로토타입 메서드
Person.prototype.sayHello = function () {
console.log(`HI, My name is ${this.name}`);
};
// 정적 프로퍼티
Person.staticProp = "인간 생성자 함수의 정적 프로퍼티 !";
// 정적 메서드
Person.staticMethod = function () {
console.log("인간 생성자 함수의 정적 메서드 호출 !");
};
const me = new Person("WI");
Person.staticMethod(); // 인간 생성자 함수의 정적 메서드 호출 !
me.staticMethod(); // TypeError: me.staticMethod is not a function
객체 내에 특정 프로터피가 존재하는지 여부 확인
key in object
console.log("name" in person); // true
console.log("age" in person);
console.log("address" in person); //false
// toString 메서드는 person 객체의 프로퍼티에는 존재하지 않는다.
// 하지만, person 객체의 프로토타입인 Object.prototype 에 toString 메서드가 존재하기 때문에 true
// 이처럼, in 연산자는 조사할 객체의 상속받은 프로토타입의 프로퍼티까지 조사를 한다.
console.log("toString" in person); // true 🔍
in 연산자와 동일하게
객체 내에 특정 프로퍼티가 존재하는 여부 확인
객체 고유의 프로퍼티 키 인 경우에만 true 반환
상속받은 프로토타입의 프로퍼티 키인 경우는 false 반환
const person = {
name: "WI",
age: 100,
};
console.log(person.hasOwnProperty("name")); // true
console.log(person.hasOwnProperty("age")); // true
// toString 메서드는 person 객체의 프로퍼티에 존재하지 않는다.
// 객체의 고유 프로퍼티일 때만 true 를 반환하는 Object.prototype.hasOwnProperty 메서드는 false 를 반환
// toString 은 person 객체에 존재하는 것이 아닌, 그에 상속된 Object.prototype 에 메서드이기 때문이다.
console.log(person.hasOwnProperty("toString")); // false 🔍
객체의 모든 프로퍼티를 순회하며 열거 할 필요가 있을 때 사용
for (변수선언문 in 객체) { ... }
for - in문은 순서를 보장하지 않는다.
객체의 프로토타입 체인 상에 존재하는 모든 프로토타입의 프로퍼티 중에서
const person = {
name : "WI",
age : 100,
__proto__ : {
address : "Incheon"
}
};
for(const key in person){
console.log(`${key} : ${person[key]}`);
}
1. __proto__로 person 객체의 프로토타입에 프로퍼티로 address 프로퍼티를 추가했다.
// in 연산자로 person 객체에 toString 프로퍼티(메서드)가 존재하는지 확인 -> 존재(true)
console.log("toString" in person); // true
1. 그럼에도 불구하고, toString 메서드는 for - in 문에서 key 에 할당되지 않았다.
2. 이는 toString 의 프로퍼티 어트리뷰트에서 [[Enumerable]] 값이 false 로 설정되어 있기 때문이다.
---
/*
name : WI
age : 100
address : Incheon
*/
오로지 객체의 프로퍼티 키들로만 for-in문을 순회하고 싶을 떄는
Object.prototype.hasOwnProperty
메소드를 호출하며 검사한다.
const person = {
name : "WI",
age : 100,
__proto__ : {
address : "Incheon"
}
};
for(const key in person){
if(person.hasOwnProperty(key)){
console.log(`${key} : ${person[key]}`);
}
}
1. person 객체의 ** 고유 프로퍼티 ** 일 경우에만 정보를 출력한다.
2. __proto__가 나오지 않음 --> 고유 프로퍼티라는 점을 참고할것
Object.keys() : 객체 자신의 열거 가능한 프로퍼티 키를 배열로 반환 ( ES6+ )
Object.values() : 객체 자신의 열거 가능한 프로퍼티 값을 배열로 반환 ( ES8 )
Object.entries() : 객체 자신의 열거 가능한 프로퍼티 키,값을 배열로 반환 ( ES8 )
const person = {
name: "WI",
age: 100,
__proto__: {
address: "Incheon",
},
};
console.log(Object.keys(person)); // [ 'name', 'age' ]
console.log(Object.values(person)); // [ 'WI', 100 ]
console.log(Object.entries(person)); // [ [ 'name', 'WI' ], [ 'age', 100 ] ]