[JS] 객체 지향 - 생성자와 new, 전역객체, this, 상속, prototype
[강의 출처] opentutorials.org/course/743/6584
객체지향 - 생활코딩
객체지향 프로그래밍은 크고 견고한 프로그램을 만들기 위한 노력의 산물이다. 객체지향이라는 큰 흐름은 현대적 프로그래밍 언어들을 지배하고 있는 가장 중요한 맥락이라고 할 수 있다. 하지
opentutorials.org
객체 지향 프로그래밍(Object Oriented Programming)
-프로젝트가 확장되면서 기존의 절차적인 방법으로 정리하기 어려워질 때, 기능별로 로직을 구분해서 정리하는 방식 중 하나
-해당 문법과 설계방식(문제의 복잡성을 적절히 단순화하여 설계하는 추상화(abstract)와 그룹핑, 캡슐화 등)을 아우르는 개념
-JS는 Prototype-based Programming에 속함
생성자(constructor)와 new
-일반적으로 객체를 만드는 방법은 아래와 같다.
var person = {
'name' = 'a';
'introduce' = function(){
return 'My name is ' + this.name;
}
}
document.write(person.introduce());
-만약 person이라는 형식으로 객체를 여러 개 만들고 싶다면 생성자를 이용한다.
-생성자(constructor)는 객체를 만드는 함수다. 자바스크립트에는 클래스가 없기 때문에 생성자는 객체와 독립적이다.
function Person(); // 함수를 정의
var p = new Person(); // 새로운 객체가 생성된다
p.name = 'a';
p.introduce = function(){
return 'My name is ' + this.name;
}
-아래처럼 생성자로 쓰일 함수를 정의할 때, 필요한 로직(메소드와 프로퍼티 등)을 정의해두면 편리하게 객체를 생성할 수 있다.
이런 작업을 초기화(initialize)라고 부른다.
function Person(name){ // 생성자로 쓰일 함수 정의
this.name = name;
this.introduce = function(){ // 여기서 메소드를 정의해두면
return 'My name is ' + this.name; // 이후 선언되는 객체들에서 반복적으로 사용가능
} // 이런 초기 세팅을 '초기화'라고 부름
};
var p1 = new Person('a'); // 생성자 Person에서 프로퍼티를 'a'로 정의
var p2 = new Person('b');
document.write(p1.introduce() + "<br />");
document.write(p2.introduce() + "<br />");
전역객체(Global Object)
-자바스크립트의 모든 객체(전역변수 및 함수를 포함해서)는 window 객체의 프로퍼티다. [참고페이지]
-node.js에서는 전역객체를 global라고 부른다.
function func(){
console.log('Hello?');
};
func(); // 'Hello?'
window.func(); // 'Hello?'
this
-함수 내에서 함수를 호출한 맥락(context)의 객체를 가리킨다. this를 통해 함수와 객체를 연결시킬 수 있다.
/* 별다른 맥락이 없는 경우, 전역객체인 window를 가리킨다 */
function func(){
if(window === this){
console.log("window === this")
}
}
func(); // window === this
/* 객체에 소속된 메소드의 this는 그 객체를 가리킨다 */
var o = {
func: function(){
if(o === this){
console.log("o === this");
}
}
}
o.func(); // o === this
-this는 객체 생성이 끝나서 어떤 식별자에 담기기 이전에도(객체 생성 진행 중에도) 해당 객체에 접근이 가능하다.
/* 생성자 안에서 this는 생성될 객체를 가리킨다*/
var funcThis = null; // 다른 함수에서도 불러와야 하니까 일단 전역변수로 세팅
function Func(){
funcThis = this; // 여기에서 this의 값으로 funcThis 재할당
}
var o1 = Func(); // new 없이 생성한 경우
if(funcThis === window){ // 함수 Func() 맥락에서 그 함수의 객체는 window가 됨
console.log('window'); // 'window'
}
var o2 = new Func(); // 생성자를 이용해 생성한 경우
if(funcThis === o2){ // 호출한 시점에서 비어있는 {} 객체가 만들어지고, 그 객체가 생성자 내의 this
console.log('o2'); // 'o2'
function Func(){
console.log(o);
}
var o = new Func(); // undefined
// 이 경우 호출이 모두 끝나야 var o가 할당완료되고, this가 o가 되는데,
// 생성 중간에 o를 호출한 것이므로 아직 정의되지 않았다고 출력된다.
-함수의 메소드 apply, call를 통해, 타 객체의 메소드를 적용 가능함
*리터럴(literal)의 개념
new로 객체를 정의하지 않고 일반적인 방법으로 객체를 생성하는 경우 ~ 리터럴이라고 부른다
// 함수 리터럴(function literal)
function sum(x,y){
return x+y;
}
// 객체 리터럴
var o = { }
var p = { }
// 배열 리터럴
var a = [1, 2, 3];
var o = {}
var p = {}
function func(){
switch(this){
case o:
console.log('o');
break;
case p:
console.log('p');
break;
case window:
console.log('window');
break;
}
}
func(); // 'window'
func.apply(o); // 'o'
func.apply(p); // 'p'
/* apply가 사용된 맥락에 따라 window.func(), o.func(), p.func()처럼 해석됨 */
상속(inheritance)
-어떤 객체의 로직(메소드, 프로퍼티 등)을 prototype 객체를 통해 다른 객체에게 물려줄 수 있는 기능
-상속을 통해 기존 객체로부터 새로운 파생 객체를 만들 수 있음
function Person(name){
this.name = name;
}
Person.prototype.name = null; // 빌트인 메소드 prototype으로 프로퍼티 추가도 가능
Person.prototype.introduce = function(){
return 'My name is ' +this.name;
}
function Programmer(name){
this.name = name;
}
Programmer.prototype = new Person(); // 이렇게 해서 Person의 로직을 상속 받음
Programmer.prototype.coding = function(){ // 상속받은 부모 객체의 prototype을 복사
return "hello world!"; // coding()은 Programmer만 실행 가능한 메소드
}
function Designer(name){
this.name = name;
}
Designer.prototype = new Person();
Designer.prototype.design = function(){ // Designer의 고유 메소드를 구현
return "beautiful!";
}
var p1 = new Programmer('a');
console.log(p1.introduce()); // My name is a. Person의 메소드를 상속 받음
console.log(p1.coding()); // hello world!
var p2 = new Designer('b');
console.log(p2.introduce()); // My name is b. Person의 메소드를 상속 받음
console.log(p2.design()); // beautiful!
console.log(p2.coding()); // Designer 객체는 coding 프로퍼티가 없으므로 에러
/* Uncaught TypeError: p2.coding is not a function */
prototype
-프로토타입 객체의 프로퍼티들은 생성자를 통해서 객체가 생성될 때 그 객체로 전달된다.
-이렇게 프로토타입을 통해 프로퍼티들이 연결되는 형태를 'prototype chain'이라고 부른다.
function Ultra(){}
Ultra.prototype.ultraProp = true;
function Super(){}
Super.prototype = new Ultra();
function Sub(){}
Sub.prototype = new Super(); // 상속받고자하는 객체를 새로 생성해서 new() 형태로 전달해야함
// Super.prototype()형태로 전달할 경우, Sub 객체의 변경사항이
var o = new Sub(); // 부모인 Super 객체에도 영향을 줄 수 있기 때문
console.log(o.ultraProp); // true