function Circle(radius) {
this.radius = radius;
this.getArea = function() {
return Math.PI * this.radius ** 2;
}
}
const circle1 = new Circle(1);
const circle2 = new Circle(2);
console.log(circle1.getArea === circle2.getArea); // false
// 생성자 함수
function Circle(radius) {
this.radius = radius;
}
// Circle 생성자 함수가 생성한 모든 인스턴스가 getArea 메서드를 공유해서 사용할 수 있도록 프로토타입에 추가한다.
// 프로토타입은 Circle 생성자 함수의 prototype 프로퍼티에 바인딩되어 있다.
Circle.prototype.getArea = function() {
return Math.PI * this.radius ** 2;
}
// 인스턴스 생성
const circle1 = new Circle(1);
const circle2 = new Circle(2);
// Circle 생성자 함수가 생성한 모든 인스턴스는 부모 객체의 역할을 하는 프로토타입 Circle.prototype으로부터 getArea 메서드를 상속받는다.
// 즉, Circle 생성자 함수가 생성하는 모든 인스턴스는 하나의 getArea 메서드를 공유한다.
console.log(circle1.getArea === circle2.getArea); // true
console.log(circle1.getArea()); // 3.141592
console.log(circle2.getArea()); // 12.56637
__proto__
접근자 프로퍼티__proto__
접근자 프로퍼티를 통해 자신의 프로토타입. 즉 [[Prototype]] 내부 슬롯에 간접적으로 접근할 수 있다.__proto__
는 접근자 프로퍼티다
__proto__
접근자 프로퍼티를 통해 접근할 수 있다.__proto__
접근자 프로퍼티는 상속을 통해 사용된다.
Object.prototype.__proto__
접근자 프로퍼티를 사용할 수 있다.__proto__
접근자 프로퍼티를 통해 프로토타입에 접근하는 이유
const parent = {};
const child = {};
child.__proto__ = parent;
parent.__proto__ = child; // TypeError
__proto__
접근자 프로퍼티를 통해 프로토타입에 접근하고 교체하도록 구현 되어 있다.__proto__
접근자 프로퍼티를 코드 내에서 직접 사용하는 것은 권장하지 않는다
__proto__
접근자 프로퍼티를 사용할 수 있는 것은 아니기 때문에, 코드내에서 직접 사용하는 것은 권장하지 않는다.__proto__
접근자 프로퍼티를 사용할 수 없는 경우가 있다.__proto__
접근자 프로퍼티 대신,const obj = {};
const parent = {x: 1};
// 객체의 프로토타입 취득
Object.getPrototypeOf(obj); // obj.__proto__;
// 객체의 프로토타입을 교체
Object.setPrototypeOf(obj, parent); // obj.__proto__ = parent;
console.log(obj.x); // 1
__proto__
접근자 프로퍼티와 함수 객체만이 가지고 있는 prototype 프로퍼티는 결국 동일한 프로토타입을 가리킨다.__proto__
접근자 프로퍼티// 생성자 함수
function Person(name) {
this.name = name;
}
const me = new Person('Lee');
console.log(Person.prototype === me.__proto__); // true
// 생성자 함수
function Person(name) {
this.name = name;
}
const me = new Person('Lee');
console.log(me.constructor === Person); // true
const obj = {};
console.log(obj.constructor === Object); // true
리터럴 표기법에 의해 생성된 객체의 생성자 함수와 프로토타입
|리터럴 표기법|생성자 함수|프로토타입|
|---|---|---|
|객체 리터럴|Object|Object.prototype|
|함수 리러털|Function|Function.prototype|
|배열 리터럴|Array|Array.prototype|
|정규 표현식 리터럴|RegExp|RegExp.prototype|
// 함수 정의가 평가되어 함수 객체를 생성하는 시점에 프로토타입도 더불이 생성된다.
console.log(Person.prototype); // {constuructor: f}
// 생성자 함수
function Person(name) {
this.name = name;
}
const Peron = name => {
this.name = name;
}
consol.log(Person.prototype); // undefined
Object.prototype
이다.const obj = { x: 1 };
Object.prototype
이다.const obj = new Object();
obj.x = 1;
프로퍼티를 추가하는 방식
에 있다.생성자 함수의 prototype 프로퍼티에 바인딩되어 있는 객체
이다.function Person(name) {
this.name = name;
}
const me = new Person('Lee');
function Person(name) {
this.name = name;
}
// 프로토타입 메서드
Person.prototype.sayHello = function() {
console.log(`Hi! My name is ${this.name}`);
};
const me = new Person('Lee');
console.log(me.hasOwnProperty('name')); // true
const Person = (function(){
// 생성자 함수
function Person(name) {
this.name = name;
}
// 프로토타입 메서드
Person.prototype.sayHello = function (){
console.log(`Hi! My name is ${this.name}`);
};
// 생성자 함수를 반환
return Person;
}());
const me = new Person('Lee');
// 인스턴스 메서드
me.sayHello = = function (){
console.log(`Hey! My name is ${this.name}`);
};
// 인스턴스 메서드가 호출 된다.
me.sayHello(); // Hey! My name is Lee
// 인스턴스 메서드를 삭제한다
delete me.sayHello;
// 인스턴스 메서드가 없으므로 프로토타입 메서드가 호출된다.
me.sayHello(); // Hi! My name is Lee
// 프로토타입 체인을 통해 프로토타입 메서드가 삭제되지 않는다
delete me.sayHello;
// 프로토타입 메서드가 호출된다.
me.sayHello(); // Hi! My name is Lee
// 프로토타입 메서드 변경
Person.prototype.sayHello = function(){
console.log(`Hey! My name is ${this.name}`);
};
me.sayHello(); // Hey! My name is Lee
// 프로토타입 메서드 삭제
delete Person.prototype.sayHello;
me.sayHello(); // TypeError
const Person = (function(){
function Person(name) {
this.name = name;
}
// 생성자 함수의 prototype 프로퍼티를 통해 프로토타입 교체
Person.prototype = {
sayHello() {
console.log(`Hi! My name is ${this.name}`);
}
}
return Person;
}());
const me = new Person('Lee');
console.log(me.constructor === Person); // false
console.log(me.constructor === Object); // true
const Person = (function(){
function Person(name) {
this.name = name;
}
// 생성자 함수의 prototype 프로퍼티를 통해 프로토타입 교체
Person.prototype = {
// constructor 프로퍼티와 생성자 함수 간의 연결을 설정
constructor: Person,
sayHello() {
console.log(`Hi! My name is ${this.name}`);
}
}
return Person;
}());
const me = new Person('Lee');
console.log(me.constructor === Person); // true
console.log(me.constructor === Object); // false
__proto__
접근자 프로퍼티를 통해 접근할 수 있고, 프로토타입을 교체할 수 있다.__proto__
접근자 프로퍼티를 통해 프로토타입을 교체하는 것은 이미 생성된 객체의 프로토타입을 교체하는 것이다.function Person(name) {
this.name = name;
}
const me = new Person('Lee');
// 프로토타입으료 교체할 객체
const parent = {
sayHello() {
console.log(`Hi! My name is ${this.name}`);
}
}
// me 객체의 프로토타입을 parent 객체로 교체한다
Object.setPrototypeOf(me, person);
// == me.__proto__ = parent;
me.sayHello(); // Hi! My name is Lee
console.log(me.constructor === Person); // false
console.log(me.constructor === Object); // true
function Person(name) {
this.name = name;
}
const me = new Person('Lee');
// 프로토타입으료 교체할 객체
const parent = {
constructor: Person,
sayHello() {
console.log(`Hi! My name is ${this.name}`);
}
}
// 생성자 함수의 prototype 프로퍼티와 프로토타입 간의 연결을 설정
Person.prototype = parent;
// me 객체의 프로토타입을 parent 객체로 교체한다
Object.setPrototypeOf(me, person);
// == me.__proto__ = parent;
me.sayHello(); // Hi! My name is Lee
// constructor 프로퍼티가 생성자 함수를 가리킨다.
console.log(me.constructor === Person); // true
console.log(me.constructor === Object); // false
// 생성자 함수의 prototype 프로퍼티가 교체된 프로토타입을 가리킨다.
console.log(Person.prototype === Object.getPrototypeOf(me)); // true
객체 instanceof 생성자 함수
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
function Person(name) {
this.name = name;
}
const me = new Person('Lee');
// 프로토타입으로 교체할 객체
const parent = {};
// 프로토타입의 교체
Object.setPrototypeOf(me, parent);
// Person 생성자 함수와 parent 객체는 연결되어 있지 않다.
console.log(Person.prototype === parent); // false
console.log(parent.constructor === Person); // false
// Person.prototype이 me 객체의 프로토타입 체인상에 존재하지 않음
console.log(me instanceof Person); // false
// Object.prototype이 me 객체의 프로토타입 체인상에 존재함
console.log(me instanceof Object); // true
const Person = (function(){
function Person(name) {
this.name = name;
}
// 생성자 함수의 prototype 프로퍼티를 통해 프로토타입을 교체
Person.prototype = {
sayHello() {
console.log(`Hi! My name is ${this.name}`);
}
}
return Person;
}());
const me = new Person('Lee');
// constructor 프로퍼티와 생성자 함수 간의 연결 파괴
console.log(me.constructor === Person);
// Person.prototype이 me 객체의 프로토타입 체인 상에 존재함
console.log(me instanceof Person); // true
// Object.prototype이 me 객체의 프로토타입 체인 상에 존재함
console.log(me instanceof Object); // true
Object.create(생성할 객체의 프로토타입으로 지정할 객체, (생성할 객체의 프로퍼티키와 디스크립터 객체로 이뤄진 객체))
// obj === {};
let 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 }
});
// obj.x = 1;
console.log(obj.x); // 1
console.log(Object.getPrototypeOf(obj) === Object.prototype); // true
__proto__
에 의한 직접 상속__proto__
접근자 프로퍼티를 사용하여 직접 상속을 구현할 수 있다.const myProto = { x: 10 };
// 객체 리터럴에 의해 객체를 생성하면서 프로토타입을 지정하여 직접 상속받을 수 있다.
const obj = {
y: 20,
// 객체를 직접 상속받는다.
// obj -> myProto -> Object.prototype -> null
__proto__: myProto
};
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 = 'static prop';
//정적 메서드
Person.staticMethod = function(){
console.log('staticMethod');
};
const me = new Person('Lee');
// 정적 프로퍼티/메서드는 생성자 함수로 참조/호출한다
Person.staticMethod(); // staticMethod
// 정적 프로퍼티/메서드는 인스턴스로 참조/호출 할수 없다.
me.staticMethod(); // TypeError
key in object
const person = {
name: 'Lee',
address: 'Seoul',
};
console.log('name' in person); // true
console.log('address' in person); // true
console.log('age' in person); // false
console.log('toString' in person); // true
const person = { name: 'Lee', };
console.log(person.hasOwnProperty('name')); // true
console.log(person.hasOwnProperty('age')); // false
console.log(person.hasOwnProperty('toString')); // false
for (변수선언문 in 객체) {...}
const person = {
name: 'Lee',
address: 'Seoul',
};
for (const key in person) {
console.log(key + ': ' + person[key]);
}
// name: Lee
// address: Seoul
const person = {
name: 'Lee',
address: 'Seoul',
__proto__: {age: 20}
};
for (const key in person) {
if (!person.hasOwnProperty(key)) continue;
console.log(key + ': ' + person[key]);
}
// name: Lee
// adress: Seoul
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