JavaScript에는 아래와 같이 네가지 instantiation pattern이 있다.
1. Functional
2. Functional-shared
3. Prototypal
4. Pseudoclassical
let Car = function(){ // 1.
let someInstance = {} // 2.
someInstance.position = 0; // 3.
someInstance.move = function(){
this.position += 1; //4.
}
return someInstance; // blueprint객체를 함수의 결과로
}
복제 될 instance들이 공통적으로 갖는 properties/Attribute & Methods/Behaviours 정의해주는 과정
PSEUDOCODE
1. 먼저 Car라는 함수를 만든다.
2. Car함수를 실행했을 때 찍어낼 객체를 선언한다.
3. someInstance의 position을 0으로 초기화해주어 찍어낸 객체들의 초기값이 항상 0이 되도록한다. 새 차니까
4. move라는 능력method를 추가해준다. method 실행 시 position값이 1만큼 증가할 것이다.
let car1 = Car();
let car2 = Car();
car1.move(); // 실행될 때마다 car1; 해보면 position이 1씩 늘어나있다.
let car1 = Car(5); // 초기 위치를 지정해줄 수도 있다.
let Car = function (position){ // 1.
let someInstance = {
position : position, // 2.
};
return someInstance;
};
// 3.
let someMethods = {};
someMethods.move = function(){
this.position += 1;
};
// 4.
let extend = function (to, from){
for(let key in from){
to[key] = from[key];
}
}
extend(someInstance, someMethods);
PSEUDOCODE
1. 먼저 Car라는 함수를 만든다.
2. 바로 position을 property로 넣어준 채로 객체를 만든다.
3. 메소드를 담아줄 객체를 생성한다. 모든 메소드는 이 객체에 넣을 것이다.
4. someInstance와 someMethods를 합치는 extend함수를 만들어서 Car함수 내부에서 합친다.
완성된 코드
let extend = function (to, from){ // 4.
for(let key in from){
to[key] = from[key];
}
}
let someMethods = {}; // 3.
someMethods.move = function(){
this.position += 1;
};
let Car = function (position){ // 1.
let someInstance = {
position : position, // 2.
};
extend(someInstance, someMethods); // 4.
return someInstance;
};
왜 굳이 번거롭게 Functional Shared 방식을 사용할까?
이전의 Functional instantiation 함수방식은 instance생성 때마다 모든 메소드를 someInstance에게 할당하므로, 각각의 instance들이 메소드 수만큼 메모리를 더 차지한다.
근데 이 Functional Shared방식을 사용하면,
someMethods라는 객체에 있는 메소드들의 메모리 주소만 참조하기 때문에 메모리 효율이 좋아진다.
Functional instantiation
3개의 instances, 6칸의 메모리
car 1's position | someMethods >> move |
---|
car 2's position | someMethods >> move |
---|
car 3's position | someMethods >> move |
---|
Functional Shared
3개의 instances, 4칸의 메모리
car 1's position |
---|
car 2's position |
---|
car 3's position |
---|
someMethods >> move |
---|
Functional Shared
방식을 사용하면 메모리 사용이 효율적이다.
functional Shared방식과 비슷한 코드를 작성한다.
var someMethods = {};
someMethods.move = function(){
this.position ++;
};
var Car = function(position){
var someInstance = {}; //여기를 바꿀 것
someInstance.position = position;
return someInstance;
};
var someMethods = {};
someMethods.move = function(){
this.position ++;
};
var Car = function(position){
var someInstance = Object.create(someMethods); //여기만 바꿨다.
someInstance.position = position;
return someInstance;
};
var car1 = Car(5);
var car2 = Car(10);
Object.create()
은 특정 객체를 prototype으로 하는 객체 및 속성을 갖는 새 객체를 생성해주는 함수
Object.create(proto)
var Car = function (position){
this.position = position; // 1. 2.
}
Car.prototype.move = function(){
this.position++; // 3.
}
var car1 = new Car(5);
var car2 = new Car(10); // 4.
console.log(car2); // Car {position: 10}
car2.move();
car2.move();
car2.move();
console.log(car2); // Car {position: 13}
console.log(car2.position); // 13
함수가 실행될 때, 해당 scope마다 생성되는 고유한 실행컨텍스트(execution context)
new 키워드로 instance를 생성했을 때에는 해당 instance가 this의 값이 된다.
function Car(brand, name, color) {
this.brand = brand; // 이 예제에서 this는 avante
this.name = name;
this.color = color;
}
Car.prototype.drive = function() {
console.log(this.name + '가 운전을 시작합니다');
}
let avante = new Car('hyundai', 'Avante', 'black')
avante.color; // 'black'
avante.drive(); // Avante가 운전을 시작합니다
배열을 정의하는 것은 Array의 instance를 만들어내는 것과 동일하다.
let avante = new Car ('hyundai', 'avante', 'blue');
avante.color; // 'blue'
avante.drive; // avante출발!!
let arr = ['code', 'states', 'pre'];
// 따라서 let arr = new Array('code', 'states', 'pre'); 도 동일함
arr.length; // 3
arr.push('course'); // 새 element추가