: JavaScript 객체는 키-값 쌍을 가질 수 있게 해주는 데이터 구조
: 고유한 키를 가질 수 있으며 각 키는 모든 JavaScript 데이터 유형이 될 수 있는 값에 매핑
: 실제 개체와 비교할 때 펜은 색상, 디자인, 재질 등과 같은 여러 속성을 가진 개체로, Object는 특성을 정의하는 속성을 가질 수 있음
Built-in Objects
•
Numbers
•
Math
•
Date
•
String
•
Error
•
Function
•
Boolean
Prototype
: JavaScript는 흔히 프로토타입 기반 언어라 불리는데, 모든 객체들이 메소드와 속성들을 상속 받기 위한 템플릿으로써 프로토타입 객체를 가짐
: 프로토타입 객체 또한 상위 프로토타입 객체로부터 메소드와 속성을 상속받을 수 있고 그 상위도 마찬가지, 이를 프로토타입 체인이라고 부름
: 상세하게는 상속되는 속성과 메소드는 각 객체가 아닌 객체의 생성자의 prototype이라는 속성에 정의되어 있음
•
프로토타입 객체 이해하기
function Person(first, last, age, gender, interests) {
// 속성과 메소드 정의
this.first = first;
this.last = last;
//...
}
var person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);
JavaScript
복사
: 위와 같이 객체를 정의하고 해당 객체를 바탕으로 인스턴스를 생성한 후, 콘솔이나 런타임 코드 환경에서 person1.을 입력하면 해당 객체의 멤버 이름을 자동으로 팝업
: 이때 Person()에 정의된 멤버들 외에도watch, valueOf처럼 Person()의 프로토타입 객체인 Object에 정의된 다른 멤버또한 존재함을 알 수 있음
•
프로토타입 속성
: 상속 받은 멤버들이 정의된 곳
: 상속받는 멤버들은 prototype 속성에 정의되어 있음, 즉 Object.가 아닌 Object.prototype.에 들어있음, 상속생성자 솏
•
create() 다시보기
: 새 인스턴스를 생성하기 위한 메소드인 Object.create()를 사용하면 주어진 객체를 프로토타입 객체로 삼아 새로운 객체를 생성
var person2 = Object.create(person1);
person2.__proto__ //person1
JavaScript
복사
•
생성자 속성
: 모든 생성자 함수는 constructor 속성을 지닌 객체를 프로토타입 객체로 보유하고 있음 이는 원본 생성자 함수 자신을 가리키고 있는데
: 각 생성된 인스턴스에서 constructor 속성에 접근할 수 있게 해줌
person1.constructor
person2.constructor
// Person() constructor 반환, 즉 다음과 같은 용법이 가능
var person3 = new person1.constructor('Karen', 'Stephenson', 26, 'female', ['playing drums', 'mountain climbing']);
JavaScript
복사
상속과 프로토타입
: 상속 관점에서 자바스크립트의 유일한 생성자는 객체뿐, 각각의 객체는 [[Prototype]]이라는 은닉 속성을 가지는데, 자신의 프로토타입이 되는 다른 객체를 가리킴
: 그 객체의 프로토타입 또한 해당 속성을 가지고 있고 이는 결국 반복되다 null을 속성으로 가지는 오브젝트에서 끝나며 이를 프로토타입 체인의 종점이라고 함
•
프로토타입 체인을 사용한 상속
◦
속성 상속
: 자바스크립트 객체는 속성을 저장하는 동적인 “가방”과 프로토타입 객체에 대한 링크를 가짐
// o라는 객체가 있고, 속성 'a' 와 'b'를 갖고 있다고 하자.
let f = function () {
this.a = 1;
this.b = 2;
}
let o = new f(); // {a: 1, b: 2}
// f 함수의 prototype 속성 값들을 추가 하자.
f.prototype.b = 3;
f.prototype.c = 4;
// f.prototype = {b: 3, c: 4}; 라고 하지 마라, 해당 코드는 prototype chain 을 망가뜨린다.
// o.[[Prototype]]은 속성 'b'와 'c'를 가지고 있다.
// o.[[Prototype]].[[Prototype]] 은 Object.prototype 이다.
// 마지막으로 o.[[Prototype]].[[Prototype]].[[Prototype]]은 null이다.
// null은 프로토타입의 종단을 말하며 정의에 의해서 추가 [[Prototype]]은 없다.
// {a: 1, b: 2} ---> {b: 3, c: 4} ---> Object.prototype ---> null
console.log(o.a); // 1
// o는 'a'라는 속성을 가지는가? 그렇다. 속성의 값은 1이다.
console.log(o.b); // 2
// o는 'b'라는 속성을 가지는가? 그렇다. 속성의 값은 2이다.
// 프로토타입 역시 'b'라는 속성을 가지지만 이 값은 쓰이지 않는다. 이것을 "속성의 가려짐(property shadowing)" 이라고 부른다.
console.log(o.c); // 4
// o는 'c'라는 속성을 가지는가? 아니다. 프로토타입을 확인해보자.
// o.[[Prototype]]은 'c'라는 속성을 가지는가? 가지고 값은 4이다.
console.log(o.d); // undefined
// o는 'd'라는 속성을 가지는가? 아니다. 프로토타입을 확인해보자.
// o.[[Prototype]]은 'd'라는 속성을 가지는가? 아니다. 다시 프로토타입을 확인해보자.
// o.[[Prototype]].[[Prototype]]은 null이다. 찾는 것을 그만두자.
// 속성이 발견되지 않았기 때문에 undefined를 반환한다.
JavaScript
복사
: 즉 상위 프로토타입으로 체이닝되어 접근 후 속성값을 가져옴, 객체의 속성에 값을 지정하면 자기만의 속성이 생김
◦
메소드 상속
: 자바 스크립트에 메소드라는 건 없음, 하지만 자바스크립트는 객체의 속성으로 함수를 지정할 수 있고 속성값을 사용하듯 사용이 가능
: 속성 값으로 지정한 함수의 상속 역시 위에서 본 속성의 상속과 동일, 상속된 함수가 실행될 때, this라는 변수는 상속된 오브젝트를 가리킴
var o = {
a: 2,
m: function(b){
return this.a + 1;
}
};
console.log(o.m()); // 3
// o.m을 호출하면 'this' 는 o를 가리킨다.
var p = Object.create(o);
// p 는 프로토타입을 o로 가지는 오브젝트이다.
p.a = 12; // p 에 'a'라는 새로운 속성을 만들었다.
console.log(p.m()); // 13
// p.m이 호출 될 때 'this' 는 'p'를 가리킨다.
// 따라서 o의 함수 m을 상속 받으며,
// 'this.a'는 p.a를 나타내며 p의 개인 속성 'a'가 된다.
JavaScript
복사
•
객체를 생성하는 여러 방법과 프로토타입 체이닝 결과
◦
문법 생성자로 객체 생성
var o = {a: 1};
// o 객체는 프로토타입으로 Object.prototype 을 가진다.
// 이로 인해 o.hasOwnProperty('a') 같은 코드를 사용할 수 있다.
// hasOwnProperty 라는 속성은 Object.prototype 의 속성이다.
// Object.prototype 의 프로토타입은 null 이다.
// o ---> Object.prototype ---> null
var a = ["yo", "whadup", "?"];
// Array.prototype을 상속받은 배열도 마찬가지다.
// (이번에는 indexOf, forEach 등의 메소드를 가진다)
// 프로토타입 체인은 다음과 같다.
// a ---> Array.prototype ---> Object.prototype ---> null
function f(){
return 2;
}
// 함수는 Function.prototype 을 상속받는다.
// (이 프로토타입은 call, bind 같은 메소드를 가진다)
// f ---> Function.prototype ---> Object.prototype ---> null
JavaScript
복사
◦
생성자를 이용
function Graph() {
this.vertexes = [];
this.edges = [];
}
Graph.prototype = {
addVertex: function(v){
this.vertexes.push(v);
}
};
var g = new Graph();
// g 'vertexes' 와 'edges'를 속성으로 가지는 객체이다.
// 생성시 g.[[Prototype]]은 Graph.prototype의 값과 같은 값을 가진다.
JavaScript
복사
◦
Object.create 이용
var a = {a: 1};
// a ---> Object.prototype ---> null
var b = Object.create(a);
// b ---> a ---> Object.prototype ---> null
console.log(b.a); // 1 (상속됨)
var c = Object.create(b);
// c ---> b ---> a ---> Object.prototype ---> null
var d = Object.create(null);
// d ---> null
console.log(d.hasOwnProperty); // undefined이다. 왜냐하면 d는 Object.prototype을 상속받지 않기 때문이다.
JavaScript
복사
◦
class 키워드 이용
'use strict';
class Polygon {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
class Square extends Polygon {
constructor(sideLength) {
super(sideLength, sideLength);
}
get area() {
return this.height * this.width;
}
set sideLength(newLength) {
this.height = newLength;
this.width = newLength;
}
}
var square = new Square(2);
JavaScript
복사
•
프로토타입 상속의 종류
◦
위임형 상속
: 위임형 상속에서 프로토타입 객체는 다른 객체의 기반이 됨, 위임 프로토타입을 받을 경우, 새 객체는 해당 프로토타입에 대한 참조를 가지고 있음
: 새 객체의 속성에 접근할 때, 해당 객체가 직접적으로 속성을 소유하고 있는지 먼저 체크한다. 없다면 다음 순서로 [[Prototype]]을 체크
: 이 과정은 프로토타입 체인을 따라서 모든 객체의 프로토타입 체인의 최상위에 있는 객체인 Object.prototype에 도달할 때 까지 반복
class Greeter {
constructor (name) {
this.name = name || 'John Doe';
}
hello () {
return `Hello, my name is ${ this.name }`;
}
}
const george = new Greeter('George');
const msg = george.hello();
console.log(msg); // Hello, my name is George
JavaScript
복사
: 객체나 배열의 상태를 변경하게 되면 같은 프로토타입을 공유하는 모든 객체의 상태가 변경, 상태 변경이 전파되는 것을 막으려면 각 객체마다 상태 값의 복사본 필요
◦
연결형 상속
: 연결형 상속은 한 객체의 속성을 다른 객체에 모두 복사함으로써 상속을 구현, 이 상속법은 Javascript 객체의 동적 확장성을 이용한 방법
const proto = {
hello: function hello() {
return `Hello, my name is ${ this.name }`;
}
};
const george = Object.assign({}, proto, {name: 'George'});
const msg = george.hello();
console.log(msg); // Hello, my name is George
JavaScript
복사
: 연결형 상속은 매우 좋은 방법으로 클로져와 같이 사용한다면 훨씬 효과적인 상속 방식
◦
함수형 상속
: 이 방법은 새 속성들을 연결형 상속으로 쌓되 상속 기능을 Factory 함수로 만들어 사용하는 방식
// import Events from 'eventemitter3';
const rawMixin = function () {
const attrs = {};
return Object.assign(this, {
set (name, value) {
attrs[name] = value;
this.emit('change', {
prop: name,
value: value
});
},
get (name) {
return attrs[name];
}
}, Events.prototype);
};
const mixinModel = (target) => rawMixin.call(target);
const george = { name: 'george' };
const model = mixinModel(george);
model.on('change', data => console.log(data));
model.set('name', 'Sam');
/*
{
prop: 'name',
value: 'Sam'
}
*/
JavaScript
복사