이 글은 생활코딩의 JavaScript 객체 지향 프로그래밍 - 1. 수업소개 - YouTube 수업을 참고 및 정리한 글 입니다.
코드가 많아지면, 관리하기 복잡해진다! 집에 옷장, 책장, 신발장이 있듯이 코드도 나눠 관리할 필요가 있다.
객체 : 서로 연관된 변수와 함수를 그룹핑하고 이름을 붙인 것
const jiwon = {
age : 23,
gender : ‘woman’
} // 속성
jiwon.age
jiwon[‘age’]
jiwon.age = 24
delete jiwon.age
for(key in jiwon) {
console.log(key, jiwon[key])
} //jiwon.key 로 쓸 수 없는 이유 : . 다음에 변수가 올 수 없다!
Math.PI
Math.random()
Math.floor(3.9)
Math
라는 객체 안에 다양한 함수들을 지정해놓았다.// 객체 정의
var MyMath = {
PI : Math.PI,
random : () => {
return Math.random();
},
floor : (val) => {
return Math.floor(val);
}
}
// 객체 호출
MyMath.PI
var jiwon = {
first : 20,
second : 30,
sum : () => {
return this.first + this.second;
}
}
var jiwon = {
first : 20,
second : 30,
sum : () => {
return this.first + this.second;
}
}
var suhyun = {
first : 50,
second : 80,
sum : () => {
return this.first + this.second;
}
}
비슷한 구조/종류의 두 객체를 동시에 바꿔주고 싶을 때!
var jiwon = {
first : 20,
second : 30,
third: 40,
sum : () => {
return this.first + this.second + this.third;
}
}
var suhyun = {
first : 50,
second : 80,
third: 90,
sum : () => {
return this.first + this.second + this.third;
}
}
이렇게 하나하나의 객체를 일일이 수정해야한다! (매우 귀찮..)
var today = new Date('2019-04-10')
: 내부적으로 2019-04-10
이라는 데이터(상태)를 가지고 있는 Date 객체가 생성되어 today
가 된다. 이때, 그 객체 내부를 우리는 당장 볼 수는 없다.
today.getFullYear()
: 그 객체의 연도를 물어보는 메소드를 실행
생성자 함수 : 객체의 초기상태를 설정해두고, 호출 시, 앞에 new
가 붙어 객체를 생성하는 함수
constructor는 객체를 찍어내는 공장의 시스템으로서, 공장의 시스템을 바꾸면 생산물이 바뀌듯이 객체도 한번에 바뀐다.
constructor를 쓰면, 코드가 간결해지며, 재사용성이 높아진다.
// constructor 정의
function Person(first, second) {
this.first = first;
this.second = second;
this.sum = () => {
return this.first + this.second;
}
}
// constructor 호출
var jiwon = new Person(20, 30);
var suhyun = new Person(40, 80);
jiwon.sum();
자바스크립트는 prototype 기반의 언어이다!
생성자가 함수(메소드)를 가질 때, 객체를 생성할때마다(반복적으로), 내부의 메소드도 생성하기 때문에 메모리를 많이 잡아먹고, 성능이 떨어진다.
function Person(first, second) {
this.first = first;
this.second = second;
this.sum = () => {
return this.first + this.second;
}
}
var jiwon = new Person(20, 30); // sum 함수 생성 (메모리와 성능 낭비)
jiwon.sum = function() => {
return 'modified: ' + (this.first + this.second);
}
var suhyun = new Person(40, 80); // sum 함수 생성 (메모리와 성능 낭비)
suhyun.sum = function() => {
return 'modified: ' + (this.first + this.second);
}
또한, 위처럼 생성자로 만들어진 객체의 메소드를 바꿀 때, 하나하나 노가다로 작업해야 되므로, 생산성도 떨어진다.
function Person(first, second) {
this.first = first;
this.second = second;
}
Person.prototype.sum = () => {
return this.first + this.second;
} // Person으로 100개의 객체를 만들어도 sum 메소드는 이거 하나로 공유
var jiwon = new Person(20, 30);
jiwon.sum = () => {
return 'modified' + (this.first + this.second);
}
var suhyun = new Person(40, 80);
jiwon.sum
등 메소드가 호출될 때class Person {
constructor(first, second) {
this.first = first;
this.second = second;
}
}
constructor
는 클래스가 호출되어 객체가 생성될 때, 먼저 호출되는 함수class Person {
constructor(first, second) {
this.first = first;
this.second = second;
}
sum() {
return this.first + this.second;
} // prototype과 같은 효과 (객체끼리 공유)
}
var jiwon = new Person(10, 20);
jiwon.sum = () => {
return 'modified' + (this.first + this.second);
}
jiwon.sum(); // jiwon 내부에 sum 있는지 확인 후, class 내 메소드 확인
class Person {
constructor(first, second) {
this.first = first;
this.second = second;
}
sum() {
return this.first + this.second;
}
}
class PersonPlus extends Person {
avg() {
return (this.first + this.second)/2;
}
}
ex) 자식클래스에 third
라는 속성을 추가하고 싶다면
class Person {
constructor(first, second) {
this.first = first;
this.second = second;
}
sum() {
return this.first + this.second;
}
}
class PersonPlus extends Person {
constructor(first, second, third) {
this.first = first;
this.second = second;
this.third = third;
}
sum() {
return this.first + this.second + this.third;
}
avg() {
return (this.first + this.second)/2;
}
}
// 안 돌아가는 코드
super
super
에 괄호가 있으면 부모클래스의 생성자super
에 괄호가 없으면 부모클래스 자체class Person {
constructor(first, second) {
this.first = first;
this.second = second;
}
sum() {
return this.first + this.second;
}
}
class PersonPlus extends Person {
constructor(first, second, third) {
suepr(first, second, third)
this.third = third;
}
sum() {
return super.sum() + this.third;
}
avg() {
return (this.first + this.second)/2;
}
}
주류 객체 지향 언어(ex.java) 에서의 상속
: super class
의 상속을 받은 sub class
가 object
를 생성한다.
javascript 에서의 상속
: super object
가 sub object
를 상속하는 등 특정 객체가 다른 객체의 상속을 받을 수 있다!
그리고, 우리는 얼마든지 이 상속 관계를 바꿀 수 있다!
상속 관계를 바꿀때는 prototype link
만 바꿔주면 된다
* 이것이 바로 자바스크립트가 prototype base langauge 라고도 불리는 이유다!
__proto__
__proto__
를 통해서 prototype link를 걸 수 있다!var superObj = { superVal : 'super' }
var subObj = { subVal : 'sub' }
subObj.__proto__ = superObj;
console.log(subObj.subVal); // sub
console.log(subObj.superVal); // super
객체.속성
: 해당 객체가 그 속성을 찾고, 없으면, (__proto__
로 연결된) 그 객체의 부모 객체에서 속성을 찾는다.subObj.superVal = 'sub';
console.log(subObj.superVal); // sub
console.log(superObj.superVal); // super
__proto__
문법은 공식적으로 표준은 아니지만, 거의 표준이다.Object.create()
를 통해서도 prototype link를 걸 수 있다!var superObj = { superVal : 'super' }
var subObj = Object.create(superObj);
subObj.subVal = 'sub';
Object.create()
문법은 공식적으로 표준 이다.자바스크립트 디버거 기능 참고
JavaScript 객체 지향 프로그래밍 - 13.3. Object.create() - YouTube
__proto__
활용방식var jiwon = {
first : 10,
second : 20,
sum : () => {
return this.first + this.second;
}
}
var suhyun = {
first : 50,
second : 100,
avg : () => {
return (this.first + this.second)/2
}
}
suhyun.__proto__ = jiwon
console.log(suhyun.sum()) // 150
console.log(suhyun.avg()) // 75
Object.create()
활용방식var jiwon = {
first : 10,
second : 20,
sum : () => {
return this.first + this.second;
}
}
var suhyun = Object.create(jiwon);
suhyun.first = 50;
suhyun.second = 100;
suhyun.avg = () => { return (this.first + this.second)/2 };
console.log(suhyun.sum()) // 150
console.log(suhyun.avg()) // 75
prototype link
를 활용하여 런타임 와중에 상속관계를 언제든지 바꿀 수 있다!call
이라는 메소드를 갖는다.call
: 첫번째 인자에 원하는 객체를 전달하면, 실행되는 함수의 this
값을 원하는 객체로 바꿔서 실행할 수 있게 해준다!var jiwon = { first : 10, second : 20}
sum(prefix) {
// sum.call(jiwon) 으로 인해 this = jiwon 이 됨!
return prefix + (this.first + this.second);
}
console.log(sum.call(jiwon, ‘hi’));
호출할 함수.call(this가 가리키는 객체, args …)
bind
: 실행되는 함수의 this
값을 원하는 객체로 고정시키는 새로운 함수를 만들어낸다.var jiwon = { first : 10, second : 20}
sum(prefix) {
return prefix + (this.first + this.second);
}
var jiwonSum = sum.bind(jiwon, ‘->’);
console.log(jiwonSum());
// 1번
function Person(){}
// 2번
var Person = new Function();
Person
생성자를 만들면, Person
내에 prototype
이라는 프로퍼티가 생성되고, Person’s prototype(== Person.prototype)
을 만들어서 가리킨다. 그리고 이것은 constructor
는 Person
을 가리킨다. (상호참조)
Person
으로 kim과 lee 객체를 만든다면, 이것들의 __proto__
라는 프로퍼티는 Person’s prototype
를 가리키게 된다.
kim.sum()
을 호출한다면, 우선, kim
내부를 확인하고, 없다면, __proto__
가 가리키는 곳, 즉, Person’s prototype
의 내부를 확인한다.
방법 1 - 객체가 객체를 상속
방법 2 - Class 로 상속 (선호!)
kim.constructor
를 찾으면, kim
내부에 없기 때문에, __proto__
가 가리키는 Person’s prototype
의 constructor
를 찾는다. 그런데, 이 constructor
는 바로 Person
을 가리킨다.