구조적 프로그래밍 방식이 개선된 형태
작은 문제들을 해결하는 객체를 만들어 조합해 큰 문제를 해결해 나가는 Bottom - up 방식
객체 지향 특정
- 캡슐화
- 정보은닉
- 추상화
- 상속성
- 다형성
// javascript는 객체지향 언어
// 다만 다른 언어와는 달리 프로토타입 상속에 기반을 둔 OOP 언어. --> Class 문법 지원
// 상속의 필요성.. 프로토타입 체이닝을 통해
// 가장 큰 목적은 '재사용성'
// 이미 부모쪽에서 정의 된 속성과 메서드을 그대로 물려받아 재사용할 수 있다. 뿐 아니라 새로운 기능을 추가해서 기존 기능에서 더 확장 시킬 수도 있다.
// 프로토타입 체인
// proto --> 상속을 해준 부모(원형)를 가리킴(참조)
// 즉, 자식 객체가 proto가 가리키는 부모 객체의 멤버를 사용할 수 있다. === 즉 상속 받았다.
let obj1 = {
name: '부모',
age: 30,
sayHi: function() {console.log('hi' + this.name);}
};
let obj2 = {
name: '자식'
};
// obj2의 proto 속성이 참조하는 것은..? -> 최상위 prototype Object를 가리킴 // obj2객체는 new 연산자를 통해 만든것이 x
// proto 속성이 참조하는 것을 바꿀 수 있는가..? YES
obj2.proto = obj1;
console.log(obj2);
obj2.sayHi(); // hi자식
[1] : proto vs Object.getPrototypeOf()
function A() {}
let obj = new A();
console.log(obj);
console.log(obj.proto); // 프로토 출력
console.log(Object.getPrototypeOf(obj)); // 프로토 출력
// obj.proto && Object.getPrototypeOf(obj) 동일 ... 단 proto는 지원하지 않는 브라우져가 있을 수 있음.
new 연산자의 내부 동작
[1]: 내부적으로는 빈 객체를 생성한 후에 -> 같은 이름의 '프로토타입 객체'를 새로운 객체의 원형으로 설정
function Add(a,b) {
this.a = a;
this.b = b;
}
Add.prototype.plus = function () {
return this.a = this.b;
};
// 새로운 객체 생성
const add = new Add(111, 222);
console.log(add.plus()); // 333
// 내부 동작
const newObj = {};
newObj.__proto__ = Add.prototype;
Add.apply(newObj, [111, 222]);
console.log(newObj.plus()); // 333
// cf. Function.prototype.apply()
func.apply(thisArg, [argsArray])
인수들의 단일 배열을 받는다
- 이미 존재하는 함수를 호출할 때 다른 this 객체를 할당 할 수 있음.
apply를 사용해, 새로운 객체마다 메소드를 재작성할 필요없이 한 번만 작성해 다른 객체에 상속 시킬 수 있음
function Add(a,b) {
this.a = a;
this.b = b;
}
Add.prototype.plus = function () {
return this.a + this.b;
};
// 새로운 객체 생성
const add = new Add(111, 222);
console.log('add', add);
console.log(add.plus()); // 333
// 내부 동작
const newObj = {};
newObj.proto = Add.prototype;
Add.apply(newObj, [111, 222]); // Add func 객체에 a, b 요소 값을 초기화 시켜줌
console.log(newObj.plus()); // 333
* Function.prototype.bind()
** bind() 메소드가 호출되면 새로운 함수를 생성합니다. 받게되는 첫 인자의 value로는 this 키워드를 설정하고, 이어지는 인자들은 바인드된 함수의 인수에 제공됩니다
* Function.prototype.call()
** call() 메소드는 주어진 this 값 및 각각 전달된 인수와 함께 함수를 호출합니다.
* Function.prototype.apply()
[1]: 객체 리터럴
const animal = {
name: 'tiger',
age: 20
}
[2]: 생성자 함수
// 첫 글자는 관례적으로 대문자로 작성
새롭게 생성되는 객체 자신을 가리키는 것 --> this를 사용
new 연산자를 사용해서 새로운 객체 --> 생성 --> 만약 new를 안붙이면 undefined 처리 --> 객체 생성시에는 new 연산자를 꼭 사용
function Person(name, age) {
this.name =name;
this.age = age;
}
let p1 = new Person('a', 1);
let p2 = new Person('b', 2);
[3]: 생성자 함수의 내부 실행 과정
function Person(name, age) {
// this = {} // this라는 빈 객체를 하나 생성한 후에 속성을 추가.
this.name =name;
this.age = age;
// return this;
}
위외 같은 처리로 new 연산자 시에 새로운 객체를 생성
[1]: constructor 속성
이 속성은 함수를 가리킨다(참조), 즉 참조를 값으로 가지는 속성
[2]: 서로가 참조... 즉, 서로가 연결고리 역할
** 생성자 함수(Animal) (------------------------------------------) (Animal) 프로토타입 객체
[3]: new 연산자에 의해 새롭게 생성된 객체 --> 인스턴스
생성자 함수(Animal) <--> new 객체(tiger, lion)
이 둘의 관계는 딱히 없는데 중요한게 있다면, new 연산자가 생성자 함수를 이용해서 새로운 객체를 생성
하지만 이렇게 생성된 객체들의 원형(부모)는 '(Animal) 프로토타입 객체'
[4]: 인스턴스(new 객체)가 어떤 생성자 함수로 생성된 것인지 알아내는 방법?
'(Animal) 프로토타입 객체' 의 constructor <- 이게 생성자 함수를 가리키고 있으므로 이 값을 확인
// new 연산자로 새롭게 만들어진 인스턴스(객체)는 자신의 부모격인 원형(프로토타입 객체)에서 특성(속성, 메서드)
를 상속 받으므로, 당연히 프로토 타입 객체의 constructor 속성을 참조 가능