객체지향1. Object 생성기계인 constructor를 만들어 써보자
constructor 문법의 용도
1. Object를 마구 복사하고 싶을 때 사용(별로 쓸데없음)
비슷한 object를 여러개 만들 때, 오브젝트 복사를 도와준다.
var 학생1 = { name: 'Kim', age: 15 }
var 학생2 = { name: 'Kim', age: 15 }
var 학생3 = { name: 'Kim', age: 15 }
...
비슷한 학생 object를 여러개 만들려면, **contstructor라는 object 생성 기계**를 만들자.
constructor는 function 키워드를 빌려서 만든다. 함수와 다르다는 걸 보여주기 위해 관습적으로 첫글자를 대문자로 쓴다.
function Student(){ ... }
일단 알아보기 쉽게 한글인 기계 로 쓰자.
function 기계(){ // 이것은 constructor
this.name = 'Kim';
this.age = 15;
}
이게 constructor이다. 이걸 쓰면 object 마구 쓰기 가능하다.
new 기계(); // 이러면 여기에 Object가 뽑힌다.
기계를 만드려면 **this**라는 키워드가 필요하다. 여기서 this는 **새로 생성되는 object**를 뜻한다.
this.name은 새로 생성되는 오브젝트의 name에 'Kim'이라는 값을 대입해주세요,
this.age는 새로 생성되는 오브젝트의 age에 15라는 값을 대입해주세요, 라는 의미다.
즉, 새로 생성되는 object에 값을 부여할 수 있다.
그럼 한 번 오브젝트를 뽑아보자.
var 학생1 = new 기계();
console.log(학생1); // 기계 {name: 'Kim', age: 15}
이러면 이제 학생1이라는 object가 뽑힌다. **'기계'는 이 object를 만든 constructor 이름**이다.
여러 학생을 만드려면 반복문을 돌려서 만들어도 된다.
object 안에 내용이 많을 수록 이득이다.
Q. 기계로 생성되는 모든 학생 object에 sayHi()함수도 추가하고 싶어요
학생1.sayHi(); // '안녕하세요 Kim 입니다' 출력되기
구현하려면 object에 함수를 추가하면 된다.
var 학생1 = {
name: 'Kim',
age: 15,
sayHi: function(){
console.log('안녕하세요 ' + this.name + ' 입니다');
}
}
이게 모든 학생들에게도 뜨게하고 싶다면, 학생1에 하드코딩하는게아니라 constructor 기계에 추가하면 된다.
function 기계(){
this.name = 'Kim';
this.age = 15;
this.sayHi = function(){
console.log('안녕하세요 ', this.name + ' 입니다');
}
}
이제 이 함수를 실행하는 모든 학생들에게 sayHi함수를 쓸 수 있다.
이처럼 **문자나 함수나 별걸 다 넣어서 오브젝트 생성기계를 만들 수 있다**.
Q. 기계로 학생을 뽑을 때 name을 다르게 설정해주고 싶어요
function 기계(구멍){
this.name = 구멍;
this.age = 15;
this.sayHi = function(){
console.log('안녕하세요 ', this.name + ' 입니다');
}
}
함수의 파라미터로 받을 수 있는 것처럼 **함수에 파라미터를 뚫어서** 구멍에서 뭔갈 받아서 쓸 수 있다.
function 기계(이름){
this.name = 이름;
this.age = 15;
this.sayHi = function(){
console.log('안녕하세요 ', this.name + ' 입니다');
}
}
기계('Park'); // 새로운 object를 만들 때 이름자리에 Park 넣어서 만들어줌
그럼 학생 오브젝트를 생성해보자.
var 학생1 = new 기계('Park');
console.log(학생1); // 기계 {name: 'Park', age:15, sayHi: f}
학생1.sayHi(); // 안녕하세요 Park 입니다
var 학생2 = new 기계();
console.log(학생2); // 기계 {name: undefined, age:15, sayHi: f}
학생2는 name이 undefined가 나온다. 왜냐하면 함수에 파라미터를 주지 않으면 undefined가 되기 때문이다.
파라미터를 여러개 줄 수도 있다.
function 기계(이름, 나이){
this.name = 이름;
this.age = 나이;
this.sayHi = function(){
console.log('안녕하세요 ', this.name + ' 입니다');
}
}
instane
this = 기계에서 새로생성되는 오브젝트
constructor(생성자)
object 생성기계
간단 연습문제
쇼핑몰에 쓸 상품데이터를 오브젝트로 여러 개 만들고 싶습니다. 그래서 하드코딩해봤는데
var product1 = { name : 'shirts', price : 50000 };
var product2 = { name : 'pants', price : 60000 };
앞으로 몇십개를 더 만들어야해서 하드코딩은 그만두고 constructor를 만들어서 오브젝트를 뽑아내려고 합니다.
Q1. 위처럼 생긴 상품오브젝트들을 뽑아낼 수 있는 constructor를 제작해보세요.그리고 실제 상품 두개를 뽑아보십시오.
function product(name, price){
this.name = name;
this.price = price;
}
var product1 = product('shirts', 50000);
var product2 = product('pants', 60000);
Q2. 상품마다 부가세() 라는 내부 함수를 실행하면 콘솔창에 상품가격 \* 10% 만큼의 부가세금액이 출력되도록 하고 싶으면 constructor를 어떻게 수정해야할까요?
예를 들면 product1.부가세() 이렇게 쓰면 콘솔창에 5000이 출력되어야합니다.
function Product(name, price){
this.name = name;
this.price = price;
this.부가세 = function(){
console.log(this.price * 0.1);
}
}
var product1 = new Product('shirts', 50000);
var product2 = new Product('pants', 60000);
객체지향2. prototype(기계 유전자, 원형)
prototype를 사용해서 <u>상속</u>기능 만들기
기계(부모, constructor)를 사용해서, 기계가 가지고 있는 name, age, sayHi 등 속성들을 학생들(자식, instance)물려받았다.
이렇게 부모의 속성을 자식이 물려받는 기능이 하나 더 있다. prototype이다. 이건 **자바스크립트에만 있는 문법**이다.
constructor(기계)를 만들면 prototype이라는 공간이 자동으로 생긴다. 한 번 확인해보자.
![](.\images\07.png)
만든 적도 없는데 생겨있다! 얘가 바로 기계 유전자다.
내가 키가 큰 이유는 부모의 키 큰 유전자를 받았기 떄문이다. prototype도 기계의 유전자다. 그래서 **prototype에 값을 추가하면 모든 자식들이 물려받을 수 있다**.
function 기계(이름, 나이){
this.name = 이름;
this.age = 나이;
this.sayHi = function(){
console.log('안녕하세요 ', this.name + ' 입니다');
}
}
기계.prototype.gender = '남';
var 학생1 = new 기계('Park');
{기계.prototype} 오브젝트에 'gender'는 '남'인 key값을 추가한거다.
![](.\images\08.png)
학생1을 콘솔해보면 gender이 없다. 안보이지만 gender 속성을 가지고 있다. 신기해!
prototype의 원리
1. 왜 자식은 부모 유전자에 등록된 값을 사용가능한가
원리는 그냥 자바스크립트가 그렇게 동작한다고 알면 된다. 자바스크립트는 오브젝트를 이 순서로 해석하고 자료를 출력한다.
학생1.gender;
- 학생1이 직접 gender를 가지고 있는가? (가지고 있으면 출력, 없으면 2로 이동)
- 그럼 학생1의 부모 유전자(기계.prototype)가 gender를 가지고 있는가? (가지고 있으면 출력)
즉, **내가 gender가 없으면 부모 유전자에서 찾는구나~** 생각하자!
2. toString, sort 등 자바스크립트 내장함수를 사용가능한 이유
toString()
- Object/Array에 붙일 수 있는 내장함수
[1,2,3].toString(); // "1,2,3"
학생1.toString(); // "[Object object]"
array에 push, sort, toString, ... 등 내장함수를 쓸 수 있다. 대체 어떻게 해놨길래 모든 Object가 내장함수를 쓸 수 있는 걸까? 학생1을 출력하면 toString이라는 메서드는 없는데 말이다.
그러면 자바스크립트에서 오브젝트를 해석하는 순서를 다시 봐야한다.
- 학생1이 toString()을 가지고 있는가?
- 그럼 부모 유전자에 있는가?
- 그럼 부모의 부모 유전자에 있는가?
- ...
컴퓨터는 실제 내부적으로 array를 이렇게 만든다.
var arr = [1,2,3];
var arr = new Array(1,2,3);
위와 아래는 동일하다. new 키워드를 만들면 기계로부터 오브젝트를 하나 뽑아낸다. 즉 array 만드는 기계로부터 하나 뽑은거다. arr은 이제 Array 기계가 가지고 있는 모든 기능들을 상속받는다. 부모 유전자에 sort, toString, map, ... 등 모든 내장함수를 가지고 있어서 오브젝트도 쓸 수 있는 거다. arr에 sort 이런거를 부여한 적이 없는데도 말이다.
확인해보고 싶으면 Array.prototype을 입력해서 Array의 유전자를 확인해보면 된다. map, sort, 등 모든 내장함수가 다 들어있다.
메서드를 구글에 검색하면 MDN에 Array.prototype.sort()라고 뜬다. Array.prototype! 부모 유전자에 sort함수가 있다! 이제 이해가 가나요?
Object도 마찬가지다.
var obj = { name: 'Kim'};
var obj = new Object();
위 코드는 동일하다. 모든 object 자료형은 Object 부모를 이용해 이렇게 만든다. 그리고 부모유전자를 올라가서 찾아본다.
- 학생1 (toString이 없네)
- 기계.prototype (toString이 없네)
- Object.prototype (toString이 있네! -> 실행)
prototype의 특징 몇가지
1. prototype은 함수(기계)에만 몰래 생성된다
var arr = [1,2,3];
![](.\images\09.png)
Array(기계)에는 있는데, arr에는 prototype이 없다고 뜬다.
2. 내 부모 유전자(부모의 prototype)를 검사하고 싶다면 '__ proto __'
![](.\images\10.png)
3. __ prototype __ 를 이용해 부모님 강제 등록하기
var 부모 = { name: 'Kim'};
var 자식 = {};
자식.__proto__ = 부모;
자식.name; // 'Kim'
나의 부모유전자는 이걸로 해주세요~ 라고 자식에서 지정할 수 있다.
4. 콘솔창에서 알려주는 prototype chain
자식에서 부모의 유전자를 보고 싶다면 __ proto __ 에서 볼 수 있다.
학생1의 부모는 기계니까 기계의 유전자가 보인다.
![](.\images\11.png)
그리고 기계의 부모는 Object 생성자다. 그래서 Object의 유전자가 보인다.
![](.\images\12.png)
constructor, prototype 연습문제
0. 오브젝트 자료 여러개를 만들고 싶습니다.
제일 잘하는게 하드코딩이기 때문에 하드코딩해봤습니다.
var 학생1 = { name : 'Kim', age : 20 }
var 학생2 = { name : 'Park', age : 21 }
var 학생3 = { name : 'Lee', age : 22 }
하드코딩해서 3개를 만들긴 했는데 앞으로 만들일이 더 많이 생길 것 같아서 constructor를 제작하려고 합니다.
**constructor문법을 사용해서 위의 오브젝트와 똑같은 오브젝트 3개를 한번 뽑아보십시오.**
**+ 여기에 학생1.sayHi()라고 사용하면 "안녕 나는 Kim이야" 라는 글자가 콘솔창에 나오도록 sayHi()라는 함수도 constructor 안에 추가해보세요.**
➡️
function Student (name, age){
this.name = name;
this.age = age;
this.sayHi: function(){
console.log('안녕 나는' + this.name + '이야')
}
}
var 학생1 = new Student('Kim', 20);
var 학생2 = new Student('Park', 21);
var 학생3 = new Student('Lee', 22);
1. 다음 코드의 출력 결과는 무엇일까요?
function Parent(){
this.name = 'Kim';
}
var a = new Parent();
a.__proto__.name = 'Park';
console.log(a.name)
**➡️ 'Kim'**
첫 4 줄에 의해서 a = {name: 'Kim'}이 되고,
a.__ proto __.name = 'Park'; 이건 **부모 prototype에 {name: 'Park'} 이걸 추가하라는 뜻**이다.
그럼 이제 a.name 이라고 사용했을 때,
**내가 직접 가지고 있는 {name: 'Kim'}** 이걸 우선 출력해준다. (이미 a는 name에 'Kim'을 가지고 있는 상태이기 때문)
2. 함수가 안들어가요 엉엉
위에 0번 문제에서 Student라는 부모에 sayHi라는 함수를 하나 추가하라고 했죠?
그래서 sayHi()라고 사용하면 "안녕 나는 ~~이야" 라고 내 이름을 출력해주는 함수를 prototype에 추가했습니다.
하단처럼 만들었는데 의도한 대로 이름이 출력되지 않고 있습니다.
원인은 무엇일까요?
function Student(이름, 나이){
this.name = 이름;
this.age = 나이;
}
Student.prototype.sayHi = () => {
console.log('안녕 나는 ' + this.name + '이야');
}
var 학생1 = new Student('Kim', 20);
학생1.sayHi(); //왜 이 코드가 제대로 안나오죠?
**➡️화살표 함수로 만들었기 때문에 this.name이 constructor Student의 name이 아니기 때문이다.**
SayHi() 라는 함수를 prototype에 추가할 때 arrow function을 사용했다. 결론부터 말하자면 arrow function은 그냥 일반 function 대체품이 아니다. arrow function은 this 를 바깥에 있는 this를 그대로 사용하고 싶을 때 쓰는 함수라 했다.
암튼 sayHi() 함수를 만들 때 arrow function을 사용해서 내부에 있던 this 값이 이상해진거다.
Student.prototype.sayHi = () => {
console.log(this); // {window}
}
window가 출력된다(strict mode에선 undefined). arrow function은 그냥 바깥 아메두나 있던 값을 가져와서 사용하기 때문이다. Student 함수에서 this는 바깥의 this인 window고, 그 window를 저기 화살표 함수 안에 적용했으니까 this가 window다.
(**object안에 들어있는 함수 안에 있는 this**는 **함수를 부른 object**가 된다)
3. 모든 array에 적용할 수 있는 함수를 직접 새로 만들려면 어떻게 해야할까요?
모든 array에 붙일 수 있는,
array 내에 있는 3이라는 값을 제거해주는 유용한 함수를 하나 만들고 싶습니다.
var arr = [1,2,3];
arr.remove3();
console.log(arr); //[1,2]
이렇게 array뒤에 붙이기만 하면 array 내의 3이라는 모든 숫자 자료들이 삭제됩니다.
멋있게 이름은 remove3() 이라고 하겠습니다.
remove3()함수는 어떻게, 어디에 만들어야 모든 array에 쓸 수 있을까요?
**➡️Array.prototype.remove3 = function(){ ... } 에 만들어야 한다.**
Array.prototype.remove3 = function(){
return this.filter(v => v !== 3)
}
애플코딩 풀이
모든 array 자로형은 부모가 ARray로 부터 new Array() 이런 식으로 만들어지기 때문에 Array라는 부모의 prototype에 있는 pop(), sort(), push(), ... 이런 함수들을 자유롭게 가져다쓸 수 있다.
그러면 우리도 Array의 prototype에 remove3이라는 함수를 하나 추가해주면 된다.
Array.prototype.remove3 = function(){
this 에서 3을 찾아서 제거해주세요
}
구현해보자.
Array.prototype.remove3 = function(){
for (var i = 0; i < this.length; i++) {
if ( this[i] === 3 ) {
this.splice(i,1);
}
}
};
var arr = [1,2,3,4];
arr.remove3();
console.log(arr); //[1,2,4]
객체지향1. Object 생성기계인 constructor를 만들어 써보자객체지향1. Object 생성기계인 constructor를 만들어 써보자
constructor 문법의 용도
1. Object를 마구 복사하고 싶을 때 사용(별로 쓸데없음)
비슷한 object를 여러개 만들 때, 오브젝트 복사를 도와준다.
var 학생1 = { name: 'Kim', age: 15 }
var 학생2 = { name: 'Kim', age: 15 }
var 학생3 = { name: 'Kim', age: 15 }
...
비슷한 학생 object를 여러개 만들려면, **contstructor라는 object 생성 기계**를 만들자.
constructor는 function 키워드를 빌려서 만든다. 함수와 다르다는 걸 보여주기 위해 관습적으로 첫글자를 대문자로 쓴다.
function Student(){ ... }
일단 알아보기 쉽게 한글인 기계 로 쓰자.
function 기계(){ // 이것은 constructor
this.name = 'Kim';
this.age = 15;
}
이게 constructor이다. 이걸 쓰면 object 마구 쓰기 가능하다.
new 기계(); // 이러면 여기에 Object가 뽑힌다.
기계를 만드려면 **this**라는 키워드가 필요하다. 여기서 this는 **새로 생성되는 object**를 뜻한다.
this.name은 새로 생성되는 오브젝트의 name에 'Kim'이라는 값을 대입해주세요,
this.age는 새로 생성되는 오브젝트의 age에 15라는 값을 대입해주세요, 라는 의미다.
즉, 새로 생성되는 object에 값을 부여할 수 있다.
그럼 한 번 오브젝트를 뽑아보자.
var 학생1 = new 기계();
console.log(학생1); // 기계 {name: 'Kim', age: 15}
이러면 이제 학생1이라는 object가 뽑힌다. **'기계'는 이 object를 만든 constructor 이름**이다.
여러 학생을 만드려면 반복문을 돌려서 만들어도 된다.
object 안에 내용이 많을 수록 이득이다.
Q. 기계로 생성되는 모든 학생 object에 sayHi()함수도 추가하고 싶어요
학생1.sayHi(); // '안녕하세요 Kim 입니다' 출력되기
구현하려면 object에 함수를 추가하면 된다.
var 학생1 = {
name: 'Kim',
age: 15,
sayHi: function(){
console.log('안녕하세요 ' + this.name + ' 입니다');
}
}
이게 모든 학생들에게도 뜨게하고 싶다면, 학생1에 하드코딩하는게아니라 constructor 기계에 추가하면 된다.
function 기계(){
this.name = 'Kim';
this.age = 15;
this.sayHi = function(){
console.log('안녕하세요 ', this.name + ' 입니다');
}
}
이제 이 함수를 실행하는 모든 학생들에게 sayHi함수를 쓸 수 있다.
이처럼 **문자나 함수나 별걸 다 넣어서 오브젝트 생성기계를 만들 수 있다**.
Q. 기계로 학생을 뽑을 때 name을 다르게 설정해주고 싶어요
function 기계(구멍){
this.name = 구멍;
this.age = 15;
this.sayHi = function(){
console.log('안녕하세요 ', this.name + ' 입니다');
}
}
함수의 파라미터로 받을 수 있는 것처럼 **함수에 파라미터를 뚫어서** 구멍에서 뭔갈 받아서 쓸 수 있다.
function 기계(이름){
this.name = 이름;
this.age = 15;
this.sayHi = function(){
console.log('안녕하세요 ', this.name + ' 입니다');
}
}
기계('Park'); // 새로운 object를 만들 때 이름자리에 Park 넣어서 만들어줌
그럼 학생 오브젝트를 생성해보자.
var 학생1 = new 기계('Park');
console.log(학생1); // 기계 {name: 'Park', age:15, sayHi: f}
학생1.sayHi(); // 안녕하세요 Park 입니다
var 학생2 = new 기계();
console.log(학생2); // 기계 {name: undefined, age:15, sayHi: f}
학생2는 name이 undefined가 나온다. 왜냐하면 함수에 파라미터를 주지 않으면 undefined가 되기 때문이다.
파라미터를 여러개 줄 수도 있다.
function 기계(이름, 나이){
this.name = 이름;
this.age = 나이;
this.sayHi = function(){
console.log('안녕하세요 ', this.name + ' 입니다');
}
}
instane
this = 기계에서 새로생성되는 오브젝트
constructor(생성자)
object 생성기계
간단 연습문제
쇼핑몰에 쓸 상품데이터를 오브젝트로 여러 개 만들고 싶습니다. 그래서 하드코딩해봤는데
var product1 = { name : 'shirts', price : 50000 };
var product2 = { name : 'pants', price : 60000 };
앞으로 몇십개를 더 만들어야해서 하드코딩은 그만두고 constructor를 만들어서 오브젝트를 뽑아내려고 합니다.
Q1. 위처럼 생긴 상품오브젝트들을 뽑아낼 수 있는 constructor를 제작해보세요.그리고 실제 상품 두개를 뽑아보십시오.
function product(name, price){
this.name = name;
this.price = price;
}
var product1 = product('shirts', 50000);
var product2 = product('pants', 60000);
Q2. 상품마다 부가세() 라는 내부 함수를 실행하면 콘솔창에 상품가격 \* 10% 만큼의 부가세금액이 출력되도록 하고 싶으면 constructor를 어떻게 수정해야할까요?
예를 들면 product1.부가세() 이렇게 쓰면 콘솔창에 5000이 출력되어야합니다.
function Product(name, price){
this.name = name;
this.price = price;
this.부가세 = function(){
console.log(this.price * 0.1);
}
}
var product1 = new Product('shirts', 50000);
var product2 = new Product('pants', 60000);
객체지향2. prototype(기계 유전자, 원형)
prototype를 사용해서 <u>상속</u>기능 만들기
기계(부모, constructor)를 사용해서, 기계가 가지고 있는 name, age, sayHi 등 속성들을 학생들(자식, instance)물려받았다.
이렇게 부모의 속성을 자식이 물려받는 기능이 하나 더 있다. prototype이다. 이건 **자바스크립트에만 있는 문법**이다.
constructor(기계)를 만들면 prototype이라는 공간이 자동으로 생긴다. 한 번 확인해보자.
![](.\images\07.png)
만든 적도 없는데 생겨있다! 얘가 바로 기계 유전자다.
내가 키가 큰 이유는 부모의 키 큰 유전자를 받았기 떄문이다. prototype도 기계의 유전자다. 그래서 **prototype에 값을 추가하면 모든 자식들이 물려받을 수 있다**.
function 기계(이름, 나이){
this.name = 이름;
this.age = 나이;
this.sayHi = function(){
console.log('안녕하세요 ', this.name + ' 입니다');
}
}
기계.prototype.gender = '남';
var 학생1 = new 기계('Park');
{기계.prototype} 오브젝트에 'gender'는 '남'인 key값을 추가한거다.
![](.\images\08.png)
학생1을 콘솔해보면 gender이 없다. 안보이지만 gender 속성을 가지고 있다. 신기해!
prototype의 원리
1. 왜 자식은 부모 유전자에 등록된 값을 사용가능한가
원리는 그냥 자바스크립트가 그렇게 동작한다고 알면 된다. 자바스크립트는 오브젝트를 이 순서로 해석하고 자료를 출력한다.
학생1.gender;
- 학생1이 직접 gender를 가지고 있는가? (가지고 있으면 출력, 없으면 2로 이동)
- 그럼 학생1의 부모 유전자(기계.prototype)가 gender를 가지고 있는가? (가지고 있으면 출력)
즉, **내가 gender가 없으면 부모 유전자에서 찾는구나~** 생각하자!
2. toString, sort 등 자바스크립트 내장함수를 사용가능한 이유
toString()
- Object/Array에 붙일 수 있는 내장함수
[1,2,3].toString(); // "1,2,3"
학생1.toString(); // "[Object object]"
array에 push, sort, toString, ... 등 내장함수를 쓸 수 있다. 대체 어떻게 해놨길래 모든 Object가 내장함수를 쓸 수 있는 걸까? 학생1을 출력하면 toString이라는 메서드는 없는데 말이다.
그러면 자바스크립트에서 오브젝트를 해석하는 순서를 다시 봐야한다.
- 학생1이 toString()을 가지고 있는가?
- 그럼 부모 유전자에 있는가?
- 그럼 부모의 부모 유전자에 있는가?
- ...
컴퓨터는 실제 내부적으로 array를 이렇게 만든다.
var arr = [1,2,3];
var arr = new Array(1,2,3);
위와 아래는 동일하다. new 키워드를 만들면 기계로부터 오브젝트를 하나 뽑아낸다. 즉 array 만드는 기계로부터 하나 뽑은거다. arr은 이제 Array 기계가 가지고 있는 모든 기능들을 상속받는다. 부모 유전자에 sort, toString, map, ... 등 모든 내장함수를 가지고 있어서 오브젝트도 쓸 수 있는 거다. arr에 sort 이런거를 부여한 적이 없는데도 말이다.
확인해보고 싶으면 Array.prototype을 입력해서 Array의 유전자를 확인해보면 된다. map, sort, 등 모든 내장함수가 다 들어있다.
메서드를 구글에 검색하면 MDN에 Array.prototype.sort()라고 뜬다. Array.prototype! 부모 유전자에 sort함수가 있다! 이제 이해가 가나요?
Object도 마찬가지다.
var obj = { name: 'Kim'};
var obj = new Object();
위 코드는 동일하다. 모든 object 자료형은 Object 부모를 이용해 이렇게 만든다. 그리고 부모유전자를 올라가서 찾아본다.
- 학생1 (toString이 없네)
- 기계.prototype (toString이 없네)
- Object.prototype (toString이 있네! -> 실행)
prototype의 특징 몇가지
1. prototype은 함수(기계)에만 몰래 생성된다
var arr = [1,2,3];
![](.\images\09.png)
Array(기계)에는 있는데, arr에는 prototype이 없다고 뜬다.
2. 내 부모 유전자(부모의 prototype)를 검사하고 싶다면 '__ proto __'
![](.\images\10.png)
3. __ prototype __ 를 이용해 부모님 강제 등록하기
var 부모 = { name: 'Kim'};
var 자식 = {};
자식.__proto__ = 부모;
자식.name; // 'Kim'
나의 부모유전자는 이걸로 해주세요~ 라고 자식에서 지정할 수 있다.
4. 콘솔창에서 알려주는 prototype chain
자식에서 부모의 유전자를 보고 싶다면 __ proto __ 에서 볼 수 있다.
학생1의 부모는 기계니까 기계의 유전자가 보인다.
![](.\images\11.png)
그리고 기계의 부모는 Object 생성자다. 그래서 Object의 유전자가 보인다.
![](.\images\12.png)
constructor, prototype 연습문제
0. 오브젝트 자료 여러개를 만들고 싶습니다.
제일 잘하는게 하드코딩이기 때문에 하드코딩해봤습니다.
var 학생1 = { name : 'Kim', age : 20 }
var 학생2 = { name : 'Park', age : 21 }
var 학생3 = { name : 'Lee', age : 22 }
하드코딩해서 3개를 만들긴 했는데 앞으로 만들일이 더 많이 생길 것 같아서 constructor를 제작하려고 합니다.
**constructor문법을 사용해서 위의 오브젝트와 똑같은 오브젝트 3개를 한번 뽑아보십시오.**
**+ 여기에 학생1.sayHi()라고 사용하면 "안녕 나는 Kim이야" 라는 글자가 콘솔창에 나오도록 sayHi()라는 함수도 constructor 안에 추가해보세요.**
➡️
function Student (name, age){
this.name = name;
this.age = age;
this.sayHi: function(){
console.log('안녕 나는' + this.name + '이야')
}
}
var 학생1 = new Student('Kim', 20);
var 학생2 = new Student('Park', 21);
var 학생3 = new Student('Lee', 22);
1. 다음 코드의 출력 결과는 무엇일까요?
function Parent(){
this.name = 'Kim';
}
var a = new Parent();
a.__proto__.name = 'Park';
console.log(a.name)
**➡️ 'Kim'**
첫 4 줄에 의해서 a = {name: 'Kim'}이 되고,
a.__ proto __.name = 'Park'; 이건 **부모 prototype에 {name: 'Park'} 이걸 추가하라는 뜻**이다.
그럼 이제 a.name 이라고 사용했을 때,
**내가 직접 가지고 있는 {name: 'Kim'}** 이걸 우선 출력해준다. (이미 a는 name에 'Kim'을 가지고 있는 상태이기 때문)
2. 함수가 안들어가요 엉엉
위에 0번 문제에서 Student라는 부모에 sayHi라는 함수를 하나 추가하라고 했죠?
그래서 sayHi()라고 사용하면 "안녕 나는 ~~이야" 라고 내 이름을 출력해주는 함수를 prototype에 추가했습니다.
하단처럼 만들었는데 의도한 대로 이름이 출력되지 않고 있습니다.
원인은 무엇일까요?
function Student(이름, 나이){
this.name = 이름;
this.age = 나이;
}
Student.prototype.sayHi = () => {
console.log('안녕 나는 ' + this.name + '이야');
}
var 학생1 = new Student('Kim', 20);
학생1.sayHi(); //왜 이 코드가 제대로 안나오죠?
**➡️화살표 함수로 만들었기 때문에 this.name이 constructor Student의 name이 아니기 때문이다.**
SayHi() 라는 함수를 prototype에 추가할 때 arrow function을 사용했다. 결론부터 말하자면 arrow function은 그냥 일반 function 대체품이 아니다. arrow function은 this 를 바깥에 있는 this를 그대로 사용하고 싶을 때 쓰는 함수라 했다.
암튼 sayHi() 함수를 만들 때 arrow function을 사용해서 내부에 있던 this 값이 이상해진거다.
Student.prototype.sayHi = () => {
console.log(this); // {window}
}
window가 출력된다(strict mode에선 undefined). arrow function은 그냥 바깥 아메두나 있던 값을 가져와서 사용하기 때문이다. Student 함수에서 this는 바깥의 this인 window고, 그 window를 저기 화살표 함수 안에 적용했으니까 this가 window다.
(**object안에 들어있는 함수 안에 있는 this**는 **함수를 부른 object**가 된다)
3. 모든 array에 적용할 수 있는 함수를 직접 새로 만들려면 어떻게 해야할까요?
모든 array에 붙일 수 있는,
array 내에 있는 3이라는 값을 제거해주는 유용한 함수를 하나 만들고 싶습니다.
var arr = [1,2,3];
arr.remove3();
console.log(arr); //[1,2]
이렇게 array뒤에 붙이기만 하면 array 내의 3이라는 모든 숫자 자료들이 삭제됩니다.
멋있게 이름은 remove3() 이라고 하겠습니다.
remove3()함수는 어떻게, 어디에 만들어야 모든 array에 쓸 수 있을까요?
**➡️Array.prototype.remove3 = function(){ ... } 에 만들어야 한다.**
Array.prototype.remove3 = function(){
return this.filter(v => v !== 3)
}
애플코딩 풀이
모든 array 자로형은 부모가 ARray로 부터 new Array() 이런 식으로 만들어지기 때문에 Array라는 부모의 prototype에 있는 pop(), sort(), push(), ... 이런 함수들을 자유롭게 가져다쓸 수 있다.
그러면 우리도 Array의 prototype에 remove3이라는 함수를 하나 추가해주면 된다.
Array.prototype.remove3 = function(){
this 에서 3을 찾아서 제거해주세요
}
구현해보자.
Array.prototype.remove3 = function(){
for (var i = 0; i < this.length; i++) {
if ( this[i] === 3 ) {
this.splice(i,1);
}
}
};
var arr = [1,2,3,4];
arr.remove3();
console.log(arr); //[1,2,4]
constructor 문법의 용도
1. Object를 마구 복사하고 싶을 때 사용(별로 쓸데없음)
비슷한 object를 여러개 만들 때, 오브젝트 복사를 도와준다.
var 학생1 = { name: 'Kim', age: 15 }
var 학생2 = { name: 'Kim', age: 15 }
var 학생3 = { name: 'Kim', age: 15 }
...
비슷한 학생 object를 여러개 만들려면, **contstructor라는 object 생성 기계**를 만들자.
constructor는 function 키워드를 빌려서 만든다. 함수와 다르다는 걸 보여주기 위해 관습적으로 첫글자를 대문자로 쓴다.
function Student(){ ... }
일단 알아보기 쉽게 한글인 기계 로 쓰자.
function 기계(){ // 이것은 constructor
this.name = 'Kim';
this.age = 15;
}
이게 constructor이다. 이걸 쓰면 object 마구 쓰기 가능하다.
new 기계(); // 이러면 여기에 Object가 뽑힌다.
기계를 만드려면 **this**라는 키워드가 필요하다. 여기서 this는 **새로 생성되는 object**를 뜻한다.
this.name은 새로 생성되는 오브젝트의 name에 'Kim'이라는 값을 대입해주세요,
this.age는 새로 생성되는 오브젝트의 age에 15라는 값을 대입해주세요, 라는 의미다.
즉, 새로 생성되는 object에 값을 부여할 수 있다.
그럼 한 번 오브젝트를 뽑아보자.
var 학생1 = new 기계();
console.log(학생1); // 기계 {name: 'Kim', age: 15}
이러면 이제 학생1이라는 object가 뽑힌다. **'기계'는 이 object를 만든 constructor 이름**이다.
여러 학생을 만드려면 반복문을 돌려서 만들어도 된다.
object 안에 내용이 많을 수록 이득이다.
Q. 기계로 생성되는 모든 학생 object에 sayHi()함수도 추가하고 싶어요
학생1.sayHi(); // '안녕하세요 Kim 입니다' 출력되기
구현하려면 object에 함수를 추가하면 된다.
var 학생1 = {
name: 'Kim',
age: 15,
sayHi: function(){
console.log('안녕하세요 ' + this.name + ' 입니다');
}
}
이게 모든 학생들에게도 뜨게하고 싶다면, 학생1에 하드코딩하는게아니라 constructor 기계에 추가하면 된다.
function 기계(){
this.name = 'Kim';
this.age = 15;
this.sayHi = function(){
console.log('안녕하세요 ', this.name + ' 입니다');
}
}
이제 이 함수를 실행하는 모든 학생들에게 sayHi함수를 쓸 수 있다.
이처럼 **문자나 함수나 별걸 다 넣어서 오브젝트 생성기계를 만들 수 있다**.
Q. 기계로 학생을 뽑을 때 name을 다르게 설정해주고 싶어요
function 기계(구멍){
this.name = 구멍;
this.age = 15;
this.sayHi = function(){
console.log('안녕하세요 ', this.name + ' 입니다');
}
}
함수의 파라미터로 받을 수 있는 것처럼 **함수에 파라미터를 뚫어서** 구멍에서 뭔갈 받아서 쓸 수 있다.
function 기계(이름){
this.name = 이름;
this.age = 15;
this.sayHi = function(){
console.log('안녕하세요 ', this.name + ' 입니다');
}
}
기계('Park'); // 새로운 object를 만들 때 이름자리에 Park 넣어서 만들어줌
그럼 학생 오브젝트를 생성해보자.
var 학생1 = new 기계('Park');
console.log(학생1); // 기계 {name: 'Park', age:15, sayHi: f}
학생1.sayHi(); // 안녕하세요 Park 입니다
var 학생2 = new 기계();
console.log(학생2); // 기계 {name: undefined, age:15, sayHi: f}
학생2는 name이 undefined가 나온다. 왜냐하면 함수에 파라미터를 주지 않으면 undefined가 되기 때문이다.
파라미터를 여러개 줄 수도 있다.
function 기계(이름, 나이){
this.name = 이름;
this.age = 나이;
this.sayHi = function(){
console.log('안녕하세요 ', this.name + ' 입니다');
}
}
instane
this = 기계에서 새로생성되는 오브젝트
constructor(생성자)
object 생성기계
간단 연습문제
쇼핑몰에 쓸 상품데이터를 오브젝트로 여러 개 만들고 싶습니다. 그래서 하드코딩해봤는데
var product1 = { name : 'shirts', price : 50000 };
var product2 = { name : 'pants', price : 60000 };
앞으로 몇십개를 더 만들어야해서 하드코딩은 그만두고 constructor를 만들어서 오브젝트를 뽑아내려고 합니다.
Q1. 위처럼 생긴 상품오브젝트들을 뽑아낼 수 있는 constructor를 제작해보세요.그리고 실제 상품 두개를 뽑아보십시오.
function product(name, price){
this.name = name;
this.price = price;
}
var product1 = product('shirts', 50000);
var product2 = product('pants', 60000);
Q2. 상품마다 부가세() 라는 내부 함수를 실행하면 콘솔창에 상품가격 \* 10% 만큼의 부가세금액이 출력되도록 하고 싶으면 constructor를 어떻게 수정해야할까요?
예를 들면 product1.부가세() 이렇게 쓰면 콘솔창에 5000이 출력되어야합니다.
function Product(name, price){
this.name = name;
this.price = price;
this.부가세 = function(){
console.log(this.price * 0.1);
}
}
var product1 = new Product('shirts', 50000);
var product2 = new Product('pants', 60000);
객체지향2. prototype(기계 유전자, 원형)
prototype를 사용해서 <u>상속</u>기능 만들기
기계(부모, constructor)를 사용해서, 기계가 가지고 있는 name, age, sayHi 등 속성들을 학생들(자식, instance)물려받았다.
이렇게 부모의 속성을 자식이 물려받는 기능이 하나 더 있다. prototype이다. 이건 **자바스크립트에만 있는 문법**이다.
constructor(기계)를 만들면 prototype이라는 공간이 자동으로 생긴다. 한 번 확인해보자.
![](.\images\07.png)
만든 적도 없는데 생겨있다! 얘가 바로 기계 유전자다.
내가 키가 큰 이유는 부모의 키 큰 유전자를 받았기 떄문이다. prototype도 기계의 유전자다. 그래서 **prototype에 값을 추가하면 모든 자식들이 물려받을 수 있다**.
function 기계(이름, 나이){
this.name = 이름;
this.age = 나이;
this.sayHi = function(){
console.log('안녕하세요 ', this.name + ' 입니다');
}
}
기계.prototype.gender = '남';
var 학생1 = new 기계('Park');
{기계.prototype} 오브젝트에 'gender'는 '남'인 key값을 추가한거다.
![](.\images\08.png)
학생1을 콘솔해보면 gender이 없다. 안보이지만 gender 속성을 가지고 있다. 신기해!
prototype의 원리
1. 왜 자식은 부모 유전자에 등록된 값을 사용가능한가
원리는 그냥 자바스크립트가 그렇게 동작한다고 알면 된다. 자바스크립트는 오브젝트를 이 순서로 해석하고 자료를 출력한다.
학생1.gender;
- 학생1이 직접 gender를 가지고 있는가? (가지고 있으면 출력, 없으면 2로 이동)
- 그럼 학생1의 부모 유전자(기계.prototype)가 gender를 가지고 있는가? (가지고 있으면 출력)
즉, **내가 gender가 없으면 부모 유전자에서 찾는구나~** 생각하자!
2. toString, sort 등 자바스크립트 내장함수를 사용가능한 이유
toString()
- Object/Array에 붙일 수 있는 내장함수
[1,2,3].toString(); // "1,2,3"
학생1.toString(); // "[Object object]"
array에 push, sort, toString, ... 등 내장함수를 쓸 수 있다. 대체 어떻게 해놨길래 모든 Object가 내장함수를 쓸 수 있는 걸까? 학생1을 출력하면 toString이라는 메서드는 없는데 말이다.
그러면 자바스크립트에서 오브젝트를 해석하는 순서를 다시 봐야한다.
- 학생1이 toString()을 가지고 있는가?
- 그럼 부모 유전자에 있는가?
- 그럼 부모의 부모 유전자에 있는가?
- ...
컴퓨터는 실제 내부적으로 array를 이렇게 만든다.
var arr = [1,2,3];
var arr = new Array(1,2,3);
위와 아래는 동일하다. new 키워드를 만들면 기계로부터 오브젝트를 하나 뽑아낸다. 즉 array 만드는 기계로부터 하나 뽑은거다. arr은 이제 Array 기계가 가지고 있는 모든 기능들을 상속받는다. 부모 유전자에 sort, toString, map, ... 등 모든 내장함수를 가지고 있어서 오브젝트도 쓸 수 있는 거다. arr에 sort 이런거를 부여한 적이 없는데도 말이다.
확인해보고 싶으면 Array.prototype을 입력해서 Array의 유전자를 확인해보면 된다. map, sort, 등 모든 내장함수가 다 들어있다.
메서드를 구글에 검색하면 MDN에 Array.prototype.sort()라고 뜬다. Array.prototype! 부모 유전자에 sort함수가 있다! 이제 이해가 가나요?
Object도 마찬가지다.
var obj = { name: 'Kim'};
var obj = new Object();
위 코드는 동일하다. 모든 object 자료형은 Object 부모를 이용해 이렇게 만든다. 그리고 부모유전자를 올라가서 찾아본다.
- 학생1 (toString이 없네)
- 기계.prototype (toString이 없네)
- Object.prototype (toString이 있네! -> 실행)
prototype의 특징 몇가지
1. prototype은 함수(기계)에만 몰래 생성된다
var arr = [1,2,3];
![](.\images\09.png)
Array(기계)에는 있는데, arr에는 prototype이 없다고 뜬다.
2. 내 부모 유전자(부모의 prototype)를 검사하고 싶다면 '__ proto __'
![](.\images\10.png)
3. __ prototype __ 를 이용해 부모님 강제 등록하기
var 부모 = { name: 'Kim'};
var 자식 = {};
자식.__proto__ = 부모;
자식.name; // 'Kim'
나의 부모유전자는 이걸로 해주세요~ 라고 자식에서 지정할 수 있다.
4. 콘솔창에서 알려주는 prototype chain
자식에서 부모의 유전자를 보고 싶다면 __ proto __ 에서 볼 수 있다.
학생1의 부모는 기계니까 기계의 유전자가 보인다.
![](.\images\11.png)
그리고 기계의 부모는 Object 생성자다. 그래서 Object의 유전자가 보인다.
![](.\images\12.png)
constructor, prototype 연습문제
0. 오브젝트 자료 여러개를 만들고 싶습니다.
제일 잘하는게 하드코딩이기 때문에 하드코딩해봤습니다.
var 학생1 = { name : 'Kim', age : 20 }
var 학생2 = { name : 'Park', age : 21 }
var 학생3 = { name : 'Lee', age : 22 }
하드코딩해서 3개를 만들긴 했는데 앞으로 만들일이 더 많이 생길 것 같아서 constructor를 제작하려고 합니다.
**constructor문법을 사용해서 위의 오브젝트와 똑같은 오브젝트 3개를 한번 뽑아보십시오.**
**+ 여기에 학생1.sayHi()라고 사용하면 "안녕 나는 Kim이야" 라는 글자가 콘솔창에 나오도록 sayHi()라는 함수도 constructor 안에 추가해보세요.**
➡️
function Student (name, age){
this.name = name;
this.age = age;
this.sayHi: function(){
console.log('안녕 나는' + this.name + '이야')
}
}
var 학생1 = new Student('Kim', 20);
var 학생2 = new Student('Park', 21);
var 학생3 = new Student('Lee', 22);
1. 다음 코드의 출력 결과는 무엇일까요?
function Parent(){
this.name = 'Kim';
}
var a = new Parent();
a.__proto__.name = 'Park';
console.log(a.name)
**➡️ 'Kim'**
첫 4 줄에 의해서 a = {name: 'Kim'}이 되고,
a.__ proto __.name = 'Park'; 이건 **부모 prototype에 {name: 'Park'} 이걸 추가하라는 뜻**이다.
그럼 이제 a.name 이라고 사용했을 때,
**내가 직접 가지고 있는 {name: 'Kim'}** 이걸 우선 출력해준다. (이미 a는 name에 'Kim'을 가지고 있는 상태이기 때문)
2. 함수가 안들어가요 엉엉
위에 0번 문제에서 Student라는 부모에 sayHi라는 함수를 하나 추가하라고 했죠?
그래서 sayHi()라고 사용하면 "안녕 나는 ~~이야" 라고 내 이름을 출력해주는 함수를 prototype에 추가했습니다.
하단처럼 만들었는데 의도한 대로 이름이 출력되지 않고 있습니다.
원인은 무엇일까요?
function Student(이름, 나이){
this.name = 이름;
this.age = 나이;
}
Student.prototype.sayHi = () => {
console.log('안녕 나는 ' + this.name + '이야');
}
var 학생1 = new Student('Kim', 20);
학생1.sayHi(); //왜 이 코드가 제대로 안나오죠?
**➡️화살표 함수로 만들었기 때문에 this.name이 constructor Student의 name이 아니기 때문이다.**
SayHi() 라는 함수를 prototype에 추가할 때 arrow function을 사용했다. 결론부터 말하자면 arrow function은 그냥 일반 function 대체품이 아니다. arrow function은 this 를 바깥에 있는 this를 그대로 사용하고 싶을 때 쓰는 함수라 했다.
암튼 sayHi() 함수를 만들 때 arrow function을 사용해서 내부에 있던 this 값이 이상해진거다.
Student.prototype.sayHi = () => {
console.log(this); // {window}
}
window가 출력된다(strict mode에선 undefined). arrow function은 그냥 바깥 아메두나 있던 값을 가져와서 사용하기 때문이다. Student 함수에서 this는 바깥의 this인 window고, 그 window를 저기 화살표 함수 안에 적용했으니까 this가 window다.
(**object안에 들어있는 함수 안에 있는 this**는 **함수를 부른 object**가 된다)
3. 모든 array에 적용할 수 있는 함수를 직접 새로 만들려면 어떻게 해야할까요?
모든 array에 붙일 수 있는,
array 내에 있는 3이라는 값을 제거해주는 유용한 함수를 하나 만들고 싶습니다.
var arr = [1,2,3];
arr.remove3();
console.log(arr); //[1,2]
이렇게 array뒤에 붙이기만 하면 array 내의 3이라는 모든 숫자 자료들이 삭제됩니다.
멋있게 이름은 remove3() 이라고 하겠습니다.
remove3()함수는 어떻게, 어디에 만들어야 모든 array에 쓸 수 있을까요?
**➡️Array.prototype.remove3 = function(){ ... } 에 만들어야 한다.**
Array.prototype.remove3 = function(){
return this.filter(v => v !== 3)
}
애플코딩 풀이
모든 array 자로형은 부모가 ARray로 부터 new Array() 이런 식으로 만들어지기 때문에 Array라는 부모의 prototype에 있는 pop(), sort(), push(), ... 이런 함수들을 자유롭게 가져다쓸 수 있다.
그러면 우리도 Array의 prototype에 remove3이라는 함수를 하나 추가해주면 된다.
Array.prototype.remove3 = function(){
this 에서 3을 찾아서 제거해주세요
}
구현해보자.
Array.prototype.remove3 = function(){
for (var i = 0; i < this.length; i++) {
if ( this[i] === 3 ) {
this.splice(i,1);
}
}
};
var arr = [1,2,3,4];
arr.remove3();
console.log(arr); //[1,2,4]
객체지향1. Object 생성기계인 constructor를 만들어 써보자
constructor 문법의 용도
1. Object를 마구 복사하고 싶을 때 사용(별로 쓸데없음)
비슷한 object를 여러개 만들 때, 오브젝트 복사를 도와준다.
var 학생1 = { name: 'Kim', age: 15 }
var 학생2 = { name: 'Kim', age: 15 }
var 학생3 = { name: 'Kim', age: 15 }
...
비슷한 학생 object를 여러개 만들려면, **contstructor라는 object 생성 기계**를 만들자.
constructor는 function 키워드를 빌려서 만든다. 함수와 다르다는 걸 보여주기 위해 관습적으로 첫글자를 대문자로 쓴다.
function Student(){ ... }
일단 알아보기 쉽게 한글인 기계 로 쓰자.
function 기계(){ // 이것은 constructor
this.name = 'Kim';
this.age = 15;
}
이게 constructor이다. 이걸 쓰면 object 마구 쓰기 가능하다.
new 기계(); // 이러면 여기에 Object가 뽑힌다.
기계를 만드려면 **this**라는 키워드가 필요하다. 여기서 this는 **새로 생성되는 object**를 뜻한다.
this.name은 새로 생성되는 오브젝트의 name에 'Kim'이라는 값을 대입해주세요,
this.age는 새로 생성되는 오브젝트의 age에 15라는 값을 대입해주세요, 라는 의미다.
즉, 새로 생성되는 object에 값을 부여할 수 있다.
그럼 한 번 오브젝트를 뽑아보자.
var 학생1 = new 기계();
console.log(학생1); // 기계 {name: 'Kim', age: 15}
이러면 이제 학생1이라는 object가 뽑힌다. **'기계'는 이 object를 만든 constructor 이름**이다.
여러 학생을 만드려면 반복문을 돌려서 만들어도 된다.
object 안에 내용이 많을 수록 이득이다.
Q. 기계로 생성되는 모든 학생 object에 sayHi()함수도 추가하고 싶어요
학생1.sayHi(); // '안녕하세요 Kim 입니다' 출력되기
구현하려면 object에 함수를 추가하면 된다.
var 학생1 = {
name: 'Kim',
age: 15,
sayHi: function(){
console.log('안녕하세요 ' + this.name + ' 입니다');
}
}
이게 모든 학생들에게도 뜨게하고 싶다면, 학생1에 하드코딩하는게아니라 constructor 기계에 추가하면 된다.
function 기계(){
this.name = 'Kim';
this.age = 15;
this.sayHi = function(){
console.log('안녕하세요 ', this.name + ' 입니다');
}
}
이제 이 함수를 실행하는 모든 학생들에게 sayHi함수를 쓸 수 있다.
이처럼 **문자나 함수나 별걸 다 넣어서 오브젝트 생성기계를 만들 수 있다**.
Q. 기계로 학생을 뽑을 때 name을 다르게 설정해주고 싶어요
function 기계(구멍){
this.name = 구멍;
this.age = 15;
this.sayHi = function(){
console.log('안녕하세요 ', this.name + ' 입니다');
}
}
함수의 파라미터로 받을 수 있는 것처럼 **함수에 파라미터를 뚫어서** 구멍에서 뭔갈 받아서 쓸 수 있다.
function 기계(이름){
this.name = 이름;
this.age = 15;
this.sayHi = function(){
console.log('안녕하세요 ', this.name + ' 입니다');
}
}
기계('Park'); // 새로운 object를 만들 때 이름자리에 Park 넣어서 만들어줌
그럼 학생 오브젝트를 생성해보자.
var 학생1 = new 기계('Park');
console.log(학생1); // 기계 {name: 'Park', age:15, sayHi: f}
학생1.sayHi(); // 안녕하세요 Park 입니다
var 학생2 = new 기계();
console.log(학생2); // 기계 {name: undefined, age:15, sayHi: f}
학생2는 name이 undefined가 나온다. 왜냐하면 함수에 파라미터를 주지 않으면 undefined가 되기 때문이다.
파라미터를 여러개 줄 수도 있다.
function 기계(이름, 나이){
this.name = 이름;
this.age = 나이;
this.sayHi = function(){
console.log('안녕하세요 ', this.name + ' 입니다');
}
}
instane
this = 기계에서 새로생성되는 오브젝트
constructor(생성자)
object 생성기계
간단 연습문제
쇼핑몰에 쓸 상품데이터를 오브젝트로 여러 개 만들고 싶습니다. 그래서 하드코딩해봤는데
var product1 = { name : 'shirts', price : 50000 };
var product2 = { name : 'pants', price : 60000 };
앞으로 몇십개를 더 만들어야해서 하드코딩은 그만두고 constructor를 만들어서 오브젝트를 뽑아내려고 합니다.
Q1. 위처럼 생긴 상품오브젝트들을 뽑아낼 수 있는 constructor를 제작해보세요.그리고 실제 상품 두개를 뽑아보십시오.
function product(name, price){
this.name = name;
this.price = price;
}
var product1 = product('shirts', 50000);
var product2 = product('pants', 60000);
Q2. 상품마다 부가세() 라는 내부 함수를 실행하면 콘솔창에 상품가격 \* 10% 만큼의 부가세금액이 출력되도록 하고 싶으면 constructor를 어떻게 수정해야할까요?
예를 들면 product1.부가세() 이렇게 쓰면 콘솔창에 5000이 출력되어야합니다.
function Product(name, price){
this.name = name;
this.price = price;
this.부가세 = function(){
console.log(this.price * 0.1);
}
}
var product1 = new Product('shirts', 50000);
var product2 = new Product('pants', 60000);
객체지향2. prototype(기계 유전자, 원형)
prototype를 사용해서 <u>상속</u>기능 만들기
기계(부모, constructor)를 사용해서, 기계가 가지고 있는 name, age, sayHi 등 속성들을 학생들(자식, instance)물려받았다.
이렇게 부모의 속성을 자식이 물려받는 기능이 하나 더 있다. prototype이다. 이건 **자바스크립트에만 있는 문법**이다.
constructor(기계)를 만들면 prototype이라는 공간이 자동으로 생긴다. 한 번 확인해보자.
![](.\images\07.png)
만든 적도 없는데 생겨있다! 얘가 바로 기계 유전자다.
내가 키가 큰 이유는 부모의 키 큰 유전자를 받았기 떄문이다. prototype도 기계의 유전자다. 그래서 **prototype에 값을 추가하면 모든 자식들이 물려받을 수 있다**.
function 기계(이름, 나이){
this.name = 이름;
this.age = 나이;
this.sayHi = function(){
console.log('안녕하세요 ', this.name + ' 입니다');
}
}
기계.prototype.gender = '남';
var 학생1 = new 기계('Park');
{기계.prototype} 오브젝트에 'gender'는 '남'인 key값을 추가한거다.
![](.\images\08.png)
학생1을 콘솔해보면 gender이 없다. 안보이지만 gender 속성을 가지고 있다. 신기해!
prototype의 원리
1. 왜 자식은 부모 유전자에 등록된 값을 사용가능한가
원리는 그냥 자바스크립트가 그렇게 동작한다고 알면 된다. 자바스크립트는 오브젝트를 이 순서로 해석하고 자료를 출력한다.
학생1.gender;
- 학생1이 직접 gender를 가지고 있는가? (가지고 있으면 출력, 없으면 2로 이동)
- 그럼 학생1의 부모 유전자(기계.prototype)가 gender를 가지고 있는가? (가지고 있으면 출력)
즉, **내가 gender가 없으면 부모 유전자에서 찾는구나~** 생각하자!
2. toString, sort 등 자바스크립트 내장함수를 사용가능한 이유
toString()
- Object/Array에 붙일 수 있는 내장함수
[1,2,3].toString(); // "1,2,3"
학생1.toString(); // "[Object object]"
array에 push, sort, toString, ... 등 내장함수를 쓸 수 있다. 대체 어떻게 해놨길래 모든 Object가 내장함수를 쓸 수 있는 걸까? 학생1을 출력하면 toString이라는 메서드는 없는데 말이다.
그러면 자바스크립트에서 오브젝트를 해석하는 순서를 다시 봐야한다.
- 학생1이 toString()을 가지고 있는가?
- 그럼 부모 유전자에 있는가?
- 그럼 부모의 부모 유전자에 있는가?
- ...
컴퓨터는 실제 내부적으로 array를 이렇게 만든다.
var arr = [1,2,3];
var arr = new Array(1,2,3);
위와 아래는 동일하다. new 키워드를 만들면 기계로부터 오브젝트를 하나 뽑아낸다. 즉 array 만드는 기계로부터 하나 뽑은거다. arr은 이제 Array 기계가 가지고 있는 모든 기능들을 상속받는다. 부모 유전자에 sort, toString, map, ... 등 모든 내장함수를 가지고 있어서 오브젝트도 쓸 수 있는 거다. arr에 sort 이런거를 부여한 적이 없는데도 말이다.
확인해보고 싶으면 Array.prototype을 입력해서 Array의 유전자를 확인해보면 된다. map, sort, 등 모든 내장함수가 다 들어있다.
메서드를 구글에 검색하면 MDN에 Array.prototype.sort()라고 뜬다. Array.prototype! 부모 유전자에 sort함수가 있다! 이제 이해가 가나요?
Object도 마찬가지다.
var obj = { name: 'Kim'};
var obj = new Object();
위 코드는 동일하다. 모든 object 자료형은 Object 부모를 이용해 이렇게 만든다. 그리고 부모유전자를 올라가서 찾아본다.
- 학생1 (toString이 없네)
- 기계.prototype (toString이 없네)
- Object.prototype (toString이 있네! -> 실행)
prototype의 특징 몇가지
1. prototype은 함수(기계)에만 몰래 생성된다
var arr = [1,2,3];
![](.\images\09.png)
Array(기계)에는 있는데, arr에는 prototype이 없다고 뜬다.
2. 내 부모 유전자(부모의 prototype)를 검사하고 싶다면 '__ proto __'
![](.\images\10.png)
3. __ prototype __ 를 이용해 부모님 강제 등록하기
var 부모 = { name: 'Kim'};
var 자식 = {};
자식.__proto__ = 부모;
자식.name; // 'Kim'
나의 부모유전자는 이걸로 해주세요~ 라고 자식에서 지정할 수 있다.
4. 콘솔창에서 알려주는 prototype chain
자식에서 부모의 유전자를 보고 싶다면 __ proto __ 에서 볼 수 있다.
학생1의 부모는 기계니까 기계의 유전자가 보인다.
![](.\images\11.png)
그리고 기계의 부모는 Object 생성자다. 그래서 Object의 유전자가 보인다.
![](.\images\12.png)
constructor, prototype 연습문제
0. 오브젝트 자료 여러개를 만들고 싶습니다.
제일 잘하는게 하드코딩이기 때문에 하드코딩해봤습니다.
var 학생1 = { name : 'Kim', age : 20 }
var 학생2 = { name : 'Park', age : 21 }
var 학생3 = { name : 'Lee', age : 22 }
하드코딩해서 3개를 만들긴 했는데 앞으로 만들일이 더 많이 생길 것 같아서 constructor를 제작하려고 합니다.
**constructor문법을 사용해서 위의 오브젝트와 똑같은 오브젝트 3개를 한번 뽑아보십시오.**
**+ 여기에 학생1.sayHi()라고 사용하면 "안녕 나는 Kim이야" 라는 글자가 콘솔창에 나오도록 sayHi()라는 함수도 constructor 안에 추가해보세요.**
➡️
function Student (name, age){
this.name = name;
this.age = age;
this.sayHi: function(){
console.log('안녕 나는' + this.name + '이야')
}
}
var 학생1 = new Student('Kim', 20);
var 학생2 = new Student('Park', 21);
var 학생3 = new Student('Lee', 22);
1. 다음 코드의 출력 결과는 무엇일까요?
function Parent(){
this.name = 'Kim';
}
var a = new Parent();
a.__proto__.name = 'Park';
console.log(a.name)
**➡️ 'Kim'**
첫 4 줄에 의해서 a = {name: 'Kim'}이 되고,
a.__ proto __.name = 'Park'; 이건 **부모 prototype에 {name: 'Park'} 이걸 추가하라는 뜻**이다.
그럼 이제 a.name 이라고 사용했을 때,
**내가 직접 가지고 있는 {name: 'Kim'}** 이걸 우선 출력해준다. (이미 a는 name에 'Kim'을 가지고 있는 상태이기 때문)
2. 함수가 안들어가요 엉엉
위에 0번 문제에서 Student라는 부모에 sayHi라는 함수를 하나 추가하라고 했죠?
그래서 sayHi()라고 사용하면 "안녕 나는 ~~이야" 라고 내 이름을 출력해주는 함수를 prototype에 추가했습니다.
하단처럼 만들었는데 의도한 대로 이름이 출력되지 않고 있습니다.
원인은 무엇일까요?
function Student(이름, 나이){
this.name = 이름;
this.age = 나이;
}
Student.prototype.sayHi = () => {
console.log('안녕 나는 ' + this.name + '이야');
}
var 학생1 = new Student('Kim', 20);
학생1.sayHi(); //왜 이 코드가 제대로 안나오죠?
**➡️화살표 함수로 만들었기 때문에 this.name이 constructor Student의 name이 아니기 때문이다.**
SayHi() 라는 함수를 prototype에 추가할 때 arrow function을 사용했다. 결론부터 말하자면 arrow function은 그냥 일반 function 대체품이 아니다. arrow function은 this 를 바깥에 있는 this를 그대로 사용하고 싶을 때 쓰는 함수라 했다.
암튼 sayHi() 함수를 만들 때 arrow function을 사용해서 내부에 있던 this 값이 이상해진거다.
Student.prototype.sayHi = () => {
console.log(this); // {window}
}
window가 출력된다(strict mode에선 undefined). arrow function은 그냥 바깥 아메두나 있던 값을 가져와서 사용하기 때문이다. Student 함수에서 this는 바깥의 this인 window고, 그 window를 저기 화살표 함수 안에 적용했으니까 this가 window다.
(**object안에 들어있는 함수 안에 있는 this**는 **함수를 부른 object**가 된다)
3. 모든 array에 적용할 수 있는 함수를 직접 새로 만들려면 어떻게 해야할까요?
모든 array에 붙일 수 있는,
array 내에 있는 3이라는 값을 제거해주는 유용한 함수를 하나 만들고 싶습니다.
var arr = [1,2,3];
arr.remove3();
console.log(arr); //[1,2]
이렇게 array뒤에 붙이기만 하면 array 내의 3이라는 모든 숫자 자료들이 삭제됩니다.
멋있게 이름은 remove3() 이라고 하겠습니다.
remove3()함수는 어떻게, 어디에 만들어야 모든 array에 쓸 수 있을까요?
**➡️Array.prototype.remove3 = function(){ ... } 에 만들어야 한다.**
Array.prototype.remove3 = function(){
return this.filter(v => v !== 3)
}
애플코딩 풀이
모든 array 자로형은 부모가 ARray로 부터 new Array() 이런 식으로 만들어지기 때문에 Array라는 부모의 prototype에 있는 pop(), sort(), push(), ... 이런 함수들을 자유롭게 가져다쓸 수 있다.
그러면 우리도 Array의 prototype에 remove3이라는 함수를 하나 추가해주면 된다.
Array.prototype.remove3 = function(){
this 에서 3을 찾아서 제거해주세요
}
구현해보자.
Array.prototype.remove3 = function(){
for (var i = 0; i < this.length; i++) {
if ( this[i] === 3 ) {
this.splice(i,1);
}
}
};
var arr = [1,2,3,4];
arr.remove3();
console.log(arr); //[1,2,4]
객체지향1. Object 생성기계인 constructor를 만들어 써보자
constructor 문법의 용도
1. Object를 마구 복사하고 싶을 때 사용(별로 쓸데없음)
비슷한 object를 여러개 만들 때, 오브젝트 복사를 도와준다.
var 학생1 = { name: 'Kim', age: 15 }
var 학생2 = { name: 'Kim', age: 15 }
var 학생3 = { name: 'Kim', age: 15 }
...
비슷한 학생 object를 여러개 만들려면, **contstructor라는 object 생성 기계**를 만들자.
constructor는 function 키워드를 빌려서 만든다. 함수와 다르다는 걸 보여주기 위해 관습적으로 첫글자를 대문자로 쓴다.
function Student(){ ... }
일단 알아보기 쉽게 한글인 기계 로 쓰자.
function 기계(){ // 이것은 constructor
this.name = 'Kim';
this.age = 15;
}
이게 constructor이다. 이걸 쓰면 object 마구 쓰기 가능하다.
new 기계(); // 이러면 여기에 Object가 뽑힌다.
기계를 만드려면 **this**라는 키워드가 필요하다. 여기서 this는 **새로 생성되는 object**를 뜻한다.
this.name은 새로 생성되는 오브젝트의 name에 'Kim'이라는 값을 대입해주세요,
this.age는 새로 생성되는 오브젝트의 age에 15라는 값을 대입해주세요, 라는 의미다.
즉, 새로 생성되는 object에 값을 부여할 수 있다.
그럼 한 번 오브젝트를 뽑아보자.
var 학생1 = new 기계();
console.log(학생1); // 기계 {name: 'Kim', age: 15}
이러면 이제 학생1이라는 object가 뽑힌다. **'기계'는 이 object를 만든 constructor 이름**이다.
여러 학생을 만드려면 반복문을 돌려서 만들어도 된다.
object 안에 내용이 많을 수록 이득이다.
Q. 기계로 생성되는 모든 학생 object에 sayHi()함수도 추가하고 싶어요
학생1.sayHi(); // '안녕하세요 Kim 입니다' 출력되기
구현하려면 object에 함수를 추가하면 된다.
var 학생1 = {
name: 'Kim',
age: 15,
sayHi: function(){
console.log('안녕하세요 ' + this.name + ' 입니다');
}
}
이게 모든 학생들에게도 뜨게하고 싶다면, 학생1에 하드코딩하는게아니라 constructor 기계에 추가하면 된다.
function 기계(){
this.name = 'Kim';
this.age = 15;
this.sayHi = function(){
console.log('안녕하세요 ', this.name + ' 입니다');
}
}
이제 이 함수를 실행하는 모든 학생들에게 sayHi함수를 쓸 수 있다.
이처럼 **문자나 함수나 별걸 다 넣어서 오브젝트 생성기계를 만들 수 있다**.
Q. 기계로 학생을 뽑을 때 name을 다르게 설정해주고 싶어요
function 기계(구멍){
this.name = 구멍;
this.age = 15;
this.sayHi = function(){
console.log('안녕하세요 ', this.name + ' 입니다');
}
}
함수의 파라미터로 받을 수 있는 것처럼 **함수에 파라미터를 뚫어서** 구멍에서 뭔갈 받아서 쓸 수 있다.
function 기계(이름){
this.name = 이름;
this.age = 15;
this.sayHi = function(){
console.log('안녕하세요 ', this.name + ' 입니다');
}
}
기계('Park'); // 새로운 object를 만들 때 이름자리에 Park 넣어서 만들어줌
그럼 학생 오브젝트를 생성해보자.
var 학생1 = new 기계('Park');
console.log(학생1); // 기계 {name: 'Park', age:15, sayHi: f}
학생1.sayHi(); // 안녕하세요 Park 입니다
var 학생2 = new 기계();
console.log(학생2); // 기계 {name: undefined, age:15, sayHi: f}
학생2는 name이 undefined가 나온다. 왜냐하면 함수에 파라미터를 주지 않으면 undefined가 되기 때문이다.
파라미터를 여러개 줄 수도 있다.
function 기계(이름, 나이){
this.name = 이름;
this.age = 나이;
this.sayHi = function(){
console.log('안녕하세요 ', this.name + ' 입니다');
}
}
instane
this = 기계에서 새로생성되는 오브젝트
constructor(생성자)
object 생성기계
간단 연습문제
쇼핑몰에 쓸 상품데이터를 오브젝트로 여러 개 만들고 싶습니다. 그래서 하드코딩해봤는데
var product1 = { name : 'shirts', price : 50000 };
var product2 = { name : 'pants', price : 60000 };
앞으로 몇십개를 더 만들어야해서 하드코딩은 그만두고 constructor를 만들어서 오브젝트를 뽑아내려고 합니다.
Q1. 위처럼 생긴 상품오브젝트들을 뽑아낼 수 있는 constructor를 제작해보세요.그리고 실제 상품 두개를 뽑아보십시오.
function product(name, price){
this.name = name;
this.price = price;
}
var product1 = product('shirts', 50000);
var product2 = product('pants', 60000);
Q2. 상품마다 부가세() 라는 내부 함수를 실행하면 콘솔창에 상품가격 \* 10% 만큼의 부가세금액이 출력되도록 하고 싶으면 constructor를 어떻게 수정해야할까요?
예를 들면 product1.부가세() 이렇게 쓰면 콘솔창에 5000이 출력되어야합니다.
function Product(name, price){
this.name = name;
this.price = price;
this.부가세 = function(){
console.log(this.price * 0.1);
}
}
var product1 = new Product('shirts', 50000);
var product2 = new Product('pants', 60000);
객체지향2. prototype(기계 유전자, 원형)
prototype를 사용해서 <u>상속</u>기능 만들기
기계(부모, constructor)를 사용해서, 기계가 가지고 있는 name, age, sayHi 등 속성들을 학생들(자식, instance)물려받았다.
이렇게 부모의 속성을 자식이 물려받는 기능이 하나 더 있다. prototype이다. 이건 **자바스크립트에만 있는 문법**이다.
constructor(기계)를 만들면 prototype이라는 공간이 자동으로 생긴다. 한 번 확인해보자.
![](.\images\07.png)
만든 적도 없는데 생겨있다! 얘가 바로 기계 유전자다.
내가 키가 큰 이유는 부모의 키 큰 유전자를 받았기 떄문이다. prototype도 기계의 유전자다. 그래서 **prototype에 값을 추가하면 모든 자식들이 물려받을 수 있다**.
function 기계(이름, 나이){
this.name = 이름;
this.age = 나이;
this.sayHi = function(){
console.log('안녕하세요 ', this.name + ' 입니다');
}
}
기계.prototype.gender = '남';
var 학생1 = new 기계('Park');
{기계.prototype} 오브젝트에 'gender'는 '남'인 key값을 추가한거다.
![](.\images\08.png)
학생1을 콘솔해보면 gender이 없다. 안보이지만 gender 속성을 가지고 있다. 신기해!
prototype의 원리
1. 왜 자식은 부모 유전자에 등록된 값을 사용가능한가
원리는 그냥 자바스크립트가 그렇게 동작한다고 알면 된다. 자바스크립트는 오브젝트를 이 순서로 해석하고 자료를 출력한다.
학생1.gender;
- 학생1이 직접 gender를 가지고 있는가? (가지고 있으면 출력, 없으면 2로 이동)
- 그럼 학생1의 부모 유전자(기계.prototype)가 gender를 가지고 있는가? (가지고 있으면 출력)
즉, **내가 gender가 없으면 부모 유전자에서 찾는구나~** 생각하자!
2. toString, sort 등 자바스크립트 내장함수를 사용가능한 이유
toString()
- Object/Array에 붙일 수 있는 내장함수
[1,2,3].toString(); // "1,2,3"
학생1.toString(); // "[Object object]"
array에 push, sort, toString, ... 등 내장함수를 쓸 수 있다. 대체 어떻게 해놨길래 모든 Object가 내장함수를 쓸 수 있는 걸까? 학생1을 출력하면 toString이라는 메서드는 없는데 말이다.
그러면 자바스크립트에서 오브젝트를 해석하는 순서를 다시 봐야한다.
- 학생1이 toString()을 가지고 있는가?
- 그럼 부모 유전자에 있는가?
- 그럼 부모의 부모 유전자에 있는가?
- ...
컴퓨터는 실제 내부적으로 array를 이렇게 만든다.
var arr = [1,2,3];
var arr = new Array(1,2,3);
위와 아래는 동일하다. new 키워드를 만들면 기계로부터 오브젝트를 하나 뽑아낸다. 즉 array 만드는 기계로부터 하나 뽑은거다. arr은 이제 Array 기계가 가지고 있는 모든 기능들을 상속받는다. 부모 유전자에 sort, toString, map, ... 등 모든 내장함수를 가지고 있어서 오브젝트도 쓸 수 있는 거다. arr에 sort 이런거를 부여한 적이 없는데도 말이다.
확인해보고 싶으면 Array.prototype을 입력해서 Array의 유전자를 확인해보면 된다. map, sort, 등 모든 내장함수가 다 들어있다.
메서드를 구글에 검색하면 MDN에 Array.prototype.sort()라고 뜬다. Array.prototype! 부모 유전자에 sort함수가 있다! 이제 이해가 가나요?
Object도 마찬가지다.
var obj = { name: 'Kim'};
var obj = new Object();
위 코드는 동일하다. 모든 object 자료형은 Object 부모를 이용해 이렇게 만든다. 그리고 부모유전자를 올라가서 찾아본다.
- 학생1 (toString이 없네)
- 기계.prototype (toString이 없네)
- Object.prototype (toString이 있네! -> 실행)
prototype의 특징 몇가지
1. prototype은 함수(기계)에만 몰래 생성된다
var arr = [1,2,3];
![](.\images\09.png)
Array(기계)에는 있는데, arr에는 prototype이 없다고 뜬다.
2. 내 부모 유전자(부모의 prototype)를 검사하고 싶다면 '__ proto __'
![](.\images\10.png)
3. __ prototype __ 를 이용해 부모님 강제 등록하기
var 부모 = { name: 'Kim'};
var 자식 = {};
자식.__proto__ = 부모;
자식.name; // 'Kim'
나의 부모유전자는 이걸로 해주세요~ 라고 자식에서 지정할 수 있다.
4. 콘솔창에서 알려주는 prototype chain
자식에서 부모의 유전자를 보고 싶다면 __ proto __ 에서 볼 수 있다.
학생1의 부모는 기계니까 기계의 유전자가 보인다.
![](.\images\11.png)
그리고 기계의 부모는 Object 생성자다. 그래서 Object의 유전자가 보인다.
![](.\images\12.png)
constructor, prototype 연습문제
0. 오브젝트 자료 여러개를 만들고 싶습니다.
제일 잘하는게 하드코딩이기 때문에 하드코딩해봤습니다.
var 학생1 = { name : 'Kim', age : 20 }
var 학생2 = { name : 'Park', age : 21 }
var 학생3 = { name : 'Lee', age : 22 }
하드코딩해서 3개를 만들긴 했는데 앞으로 만들일이 더 많이 생길 것 같아서 constructor를 제작하려고 합니다.
**constructor문법을 사용해서 위의 오브젝트와 똑같은 오브젝트 3개를 한번 뽑아보십시오.**
**+ 여기에 학생1.sayHi()라고 사용하면 "안녕 나는 Kim이야" 라는 글자가 콘솔창에 나오도록 sayHi()라는 함수도 constructor 안에 추가해보세요.**
➡️
function Student (name, age){
this.name = name;
this.age = age;
this.sayHi: function(){
console.log('안녕 나는' + this.name + '이야')
}
}
var 학생1 = new Student('Kim', 20);
var 학생2 = new Student('Park', 21);
var 학생3 = new Student('Lee', 22);
1. 다음 코드의 출력 결과는 무엇일까요?
function Parent(){
this.name = 'Kim';
}
var a = new Parent();
a.__proto__.name = 'Park';
console.log(a.name)
**➡️ 'Kim'**
첫 4 줄에 의해서 a = {name: 'Kim'}이 되고,
a.__ proto __.name = 'Park'; 이건 **부모 prototype에 {name: 'Park'} 이걸 추가하라는 뜻**이다.
그럼 이제 a.name 이라고 사용했을 때,
**내가 직접 가지고 있는 {name: 'Kim'}** 이걸 우선 출력해준다. (이미 a는 name에 'Kim'을 가지고 있는 상태이기 때문)
2. 함수가 안들어가요 엉엉
위에 0번 문제에서 Student라는 부모에 sayHi라는 함수를 하나 추가하라고 했죠?
그래서 sayHi()라고 사용하면 "안녕 나는 ~~이야" 라고 내 이름을 출력해주는 함수를 prototype에 추가했습니다.
하단처럼 만들었는데 의도한 대로 이름이 출력되지 않고 있습니다.
원인은 무엇일까요?
function Student(이름, 나이){
this.name = 이름;
this.age = 나이;
}
Student.prototype.sayHi = () => {
console.log('안녕 나는 ' + this.name + '이야');
}
var 학생1 = new Student('Kim', 20);
학생1.sayHi(); //왜 이 코드가 제대로 안나오죠?
**➡️화살표 함수로 만들었기 때문에 this.name이 constructor Student의 name이 아니기 때문이다.**
SayHi() 라는 함수를 prototype에 추가할 때 arrow function을 사용했다. 결론부터 말하자면 arrow function은 그냥 일반 function 대체품이 아니다. arrow function은 this 를 바깥에 있는 this를 그대로 사용하고 싶을 때 쓰는 함수라 했다.
암튼 sayHi() 함수를 만들 때 arrow function을 사용해서 내부에 있던 this 값이 이상해진거다.
Student.prototype.sayHi = () => {
console.log(this); // {window}
}
window가 출력된다(strict mode에선 undefined). arrow function은 그냥 바깥 아메두나 있던 값을 가져와서 사용하기 때문이다. Student 함수에서 this는 바깥의 this인 window고, 그 window를 저기 화살표 함수 안에 적용했으니까 this가 window다.
(**object안에 들어있는 함수 안에 있는 this**는 **함수를 부른 object**가 된다)
3. 모든 array에 적용할 수 있는 함수를 직접 새로 만들려면 어떻게 해야할까요?
모든 array에 붙일 수 있는,
array 내에 있는 3이라는 값을 제거해주는 유용한 함수를 하나 만들고 싶습니다.
var arr = [1,2,3];
arr.remove3();
console.log(arr); //[1,2]
이렇게 array뒤에 붙이기만 하면 array 내의 3이라는 모든 숫자 자료들이 삭제됩니다.
멋있게 이름은 remove3() 이라고 하겠습니다.
remove3()함수는 어떻게, 어디에 만들어야 모든 array에 쓸 수 있을까요?
**➡️Array.prototype.remove3 = function(){ ... } 에 만들어야 한다.**
Array.prototype.remove3 = function(){
return this.filter(v => v !== 3)
}
애플코딩 풀이
모든 array 자로형은 부모가 ARray로 부터 new Array() 이런 식으로 만들어지기 때문에 Array라는 부모의 prototype에 있는 pop(), sort(), push(), ... 이런 함수들을 자유롭게 가져다쓸 수 있다.
그러면 우리도 Array의 prototype에 remove3이라는 함수를 하나 추가해주면 된다.
Array.prototype.remove3 = function(){
this 에서 3을 찾아서 제거해주세요
}
구현해보자.
Array.prototype.remove3 = function(){
for (var i = 0; i < this.length; i++) {
if ( this[i] === 3 ) {
this.splice(i,1);
}
}
};
var arr = [1,2,3,4];
arr.remove3();
console.log(arr); //[1,2,4]
객체지향1. Object 생성기계인 constructor를 만들어 써보자
constructor 문법의 용도
1. Object를 마구 복사하고 싶을 때 사용(별로 쓸데없음)
비슷한 object를 여러개 만들 때, 오브젝트 복사를 도와준다.
var 학생1 = { name: 'Kim', age: 15 }
var 학생2 = { name: 'Kim', age: 15 }
var 학생3 = { name: 'Kim', age: 15 }
...
비슷한 학생 object를 여러개 만들려면, **contstructor라는 object 생성 기계**를 만들자.
constructor는 function 키워드를 빌려서 만든다. 함수와 다르다는 걸 보여주기 위해 관습적으로 첫글자를 대문자로 쓴다.
function Student(){ ... }
일단 알아보기 쉽게 한글인 기계 로 쓰자.
function 기계(){ // 이것은 constructor
this.name = 'Kim';
this.age = 15;
}
이게 constructor이다. 이걸 쓰면 object 마구 쓰기 가능하다.
new 기계(); // 이러면 여기에 Object가 뽑힌다.
기계를 만드려면 **this**라는 키워드가 필요하다. 여기서 this는 **새로 생성되는 object**를 뜻한다.
this.name은 새로 생성되는 오브젝트의 name에 'Kim'이라는 값을 대입해주세요,
this.age는 새로 생성되는 오브젝트의 age에 15라는 값을 대입해주세요, 라는 의미다.
즉, 새로 생성되는 object에 값을 부여할 수 있다.
그럼 한 번 오브젝트를 뽑아보자.
var 학생1 = new 기계();
console.log(학생1); // 기계 {name: 'Kim', age: 15}
이러면 이제 학생1이라는 object가 뽑힌다. **'기계'는 이 object를 만든 constructor 이름**이다.
여러 학생을 만드려면 반복문을 돌려서 만들어도 된다.
object 안에 내용이 많을 수록 이득이다.
Q. 기계로 생성되는 모든 학생 object에 sayHi()함수도 추가하고 싶어요
학생1.sayHi(); // '안녕하세요 Kim 입니다' 출력되기
구현하려면 object에 함수를 추가하면 된다.
var 학생1 = {
name: 'Kim',
age: 15,
sayHi: function(){
console.log('안녕하세요 ' + this.name + ' 입니다');
}
}
이게 모든 학생들에게도 뜨게하고 싶다면, 학생1에 하드코딩하는게아니라 constructor 기계에 추가하면 된다.
function 기계(){
this.name = 'Kim';
this.age = 15;
this.sayHi = function(){
console.log('안녕하세요 ', this.name + ' 입니다');
}
}
이제 이 함수를 실행하는 모든 학생들에게 sayHi함수를 쓸 수 있다.
이처럼 **문자나 함수나 별걸 다 넣어서 오브젝트 생성기계를 만들 수 있다**.
Q. 기계로 학생을 뽑을 때 name을 다르게 설정해주고 싶어요
function 기계(구멍){
this.name = 구멍;
this.age = 15;
this.sayHi = function(){
console.log('안녕하세요 ', this.name + ' 입니다');
}
}
함수의 파라미터로 받을 수 있는 것처럼 **함수에 파라미터를 뚫어서** 구멍에서 뭔갈 받아서 쓸 수 있다.
function 기계(이름){
this.name = 이름;
this.age = 15;
this.sayHi = function(){
console.log('안녕하세요 ', this.name + ' 입니다');
}
}
기계('Park'); // 새로운 object를 만들 때 이름자리에 Park 넣어서 만들어줌
그럼 학생 오브젝트를 생성해보자.
var 학생1 = new 기계('Park');
console.log(학생1); // 기계 {name: 'Park', age:15, sayHi: f}
학생1.sayHi(); // 안녕하세요 Park 입니다
var 학생2 = new 기계();
console.log(학생2); // 기계 {name: undefined, age:15, sayHi: f}
학생2는 name이 undefined가 나온다. 왜냐하면 함수에 파라미터를 주지 않으면 undefined가 되기 때문이다.
파라미터를 여러개 줄 수도 있다.
function 기계(이름, 나이){
this.name = 이름;
this.age = 나이;
this.sayHi = function(){
console.log('안녕하세요 ', this.name + ' 입니다');
}
}
instane
this = 기계에서 새로생성되는 오브젝트
constructor(생성자)
object 생성기계
간단 연습문제
쇼핑몰에 쓸 상품데이터를 오브젝트로 여러 개 만들고 싶습니다. 그래서 하드코딩해봤는데
var product1 = { name : 'shirts', price : 50000 };
var product2 = { name : 'pants', price : 60000 };
앞으로 몇십개를 더 만들어야해서 하드코딩은 그만두고 constructor를 만들어서 오브젝트를 뽑아내려고 합니다.
Q1. 위처럼 생긴 상품오브젝트들을 뽑아낼 수 있는 constructor를 제작해보세요.그리고 실제 상품 두개를 뽑아보십시오.
function product(name, price){
this.name = name;
this.price = price;
}
var product1 = product('shirts', 50000);
var product2 = product('pants', 60000);
Q2. 상품마다 부가세() 라는 내부 함수를 실행하면 콘솔창에 상품가격 \* 10% 만큼의 부가세금액이 출력되도록 하고 싶으면 constructor를 어떻게 수정해야할까요?
예를 들면 product1.부가세() 이렇게 쓰면 콘솔창에 5000이 출력되어야합니다.
function Product(name, price){
this.name = name;
this.price = price;
this.부가세 = function(){
console.log(this.price * 0.1);
}
}
var product1 = new Product('shirts', 50000);
var product2 = new Product('pants', 60000);
객체지향2. prototype(기계 유전자, 원형)
prototype를 사용해서 <u>상속</u>기능 만들기
기계(부모, constructor)를 사용해서, 기계가 가지고 있는 name, age, sayHi 등 속성들을 학생들(자식, instance)물려받았다.
이렇게 부모의 속성을 자식이 물려받는 기능이 하나 더 있다. prototype이다. 이건 **자바스크립트에만 있는 문법**이다.
constructor(기계)를 만들면 prototype이라는 공간이 자동으로 생긴다. 한 번 확인해보자.
![](.\images\07.png)
만든 적도 없는데 생겨있다! 얘가 바로 기계 유전자다.
내가 키가 큰 이유는 부모의 키 큰 유전자를 받았기 떄문이다. prototype도 기계의 유전자다. 그래서 **prototype에 값을 추가하면 모든 자식들이 물려받을 수 있다**.
function 기계(이름, 나이){
this.name = 이름;
this.age = 나이;
this.sayHi = function(){
console.log('안녕하세요 ', this.name + ' 입니다');
}
}
기계.prototype.gender = '남';
var 학생1 = new 기계('Park');
{기계.prototype} 오브젝트에 'gender'는 '남'인 key값을 추가한거다.
![](.\images\08.png)
학생1을 콘솔해보면 gender이 없다. 안보이지만 gender 속성을 가지고 있다. 신기해!
prototype의 원리
1. 왜 자식은 부모 유전자에 등록된 값을 사용가능한가
원리는 그냥 자바스크립트가 그렇게 동작한다고 알면 된다. 자바스크립트는 오브젝트를 이 순서로 해석하고 자료를 출력한다.
학생1.gender;
- 학생1이 직접 gender를 가지고 있는가? (가지고 있으면 출력, 없으면 2로 이동)
- 그럼 학생1의 부모 유전자(기계.prototype)가 gender를 가지고 있는가? (가지고 있으면 출력)
즉, **내가 gender가 없으면 부모 유전자에서 찾는구나~** 생각하자!
2. toString, sort 등 자바스크립트 내장함수를 사용가능한 이유
toString()
- Object/Array에 붙일 수 있는 내장함수
[1,2,3].toString(); // "1,2,3"
학생1.toString(); // "[Object object]"
array에 push, sort, toString, ... 등 내장함수를 쓸 수 있다. 대체 어떻게 해놨길래 모든 Object가 내장함수를 쓸 수 있는 걸까? 학생1을 출력하면 toString이라는 메서드는 없는데 말이다.
그러면 자바스크립트에서 오브젝트를 해석하는 순서를 다시 봐야한다.
- 학생1이 toString()을 가지고 있는가?
- 그럼 부모 유전자에 있는가?
- 그럼 부모의 부모 유전자에 있는가?
- ...
컴퓨터는 실제 내부적으로 array를 이렇게 만든다.
var arr = [1,2,3];
var arr = new Array(1,2,3);
위와 아래는 동일하다. new 키워드를 만들면 기계로부터 오브젝트를 하나 뽑아낸다. 즉 array 만드는 기계로부터 하나 뽑은거다. arr은 이제 Array 기계가 가지고 있는 모든 기능들을 상속받는다. 부모 유전자에 sort, toString, map, ... 등 모든 내장함수를 가지고 있어서 오브젝트도 쓸 수 있는 거다. arr에 sort 이런거를 부여한 적이 없는데도 말이다.
확인해보고 싶으면 Array.prototype을 입력해서 Array의 유전자를 확인해보면 된다. map, sort, 등 모든 내장함수가 다 들어있다.
메서드를 구글에 검색하면 MDN에 Array.prototype.sort()라고 뜬다. Array.prototype! 부모 유전자에 sort함수가 있다! 이제 이해가 가나요?
Object도 마찬가지다.
var obj = { name: 'Kim'};
var obj = new Object();
위 코드는 동일하다. 모든 object 자료형은 Object 부모를 이용해 이렇게 만든다. 그리고 부모유전자를 올라가서 찾아본다.
- 학생1 (toString이 없네)
- 기계.prototype (toString이 없네)
- Object.prototype (toString이 있네! -> 실행)
prototype의 특징 몇가지
1. prototype은 함수(기계)에만 몰래 생성된다
var arr = [1,2,3];
![](.\images\09.png)
Array(기계)에는 있는데, arr에는 prototype이 없다고 뜬다.
2. 내 부모 유전자(부모의 prototype)를 검사하고 싶다면 '__ proto __'
![](.\images\10.png)
3. __ prototype __ 를 이용해 부모님 강제 등록하기
var 부모 = { name: 'Kim'};
var 자식 = {};
자식.__proto__ = 부모;
자식.name; // 'Kim'
나의 부모유전자는 이걸로 해주세요~ 라고 자식에서 지정할 수 있다.
4. 콘솔창에서 알려주는 prototype chain
자식에서 부모의 유전자를 보고 싶다면 __ proto __ 에서 볼 수 있다.
학생1의 부모는 기계니까 기계의 유전자가 보인다.
![](.\images\11.png)
그리고 기계의 부모는 Object 생성자다. 그래서 Object의 유전자가 보인다.
![](.\images\12.png)
constructor, prototype 연습문제
0. 오브젝트 자료 여러개를 만들고 싶습니다.
제일 잘하는게 하드코딩이기 때문에 하드코딩해봤습니다.
var 학생1 = { name : 'Kim', age : 20 }
var 학생2 = { name : 'Park', age : 21 }
var 학생3 = { name : 'Lee', age : 22 }
하드코딩해서 3개를 만들긴 했는데 앞으로 만들일이 더 많이 생길 것 같아서 constructor를 제작하려고 합니다.
**constructor문법을 사용해서 위의 오브젝트와 똑같은 오브젝트 3개를 한번 뽑아보십시오.**
**+ 여기에 학생1.sayHi()라고 사용하면 "안녕 나는 Kim이야" 라는 글자가 콘솔창에 나오도록 sayHi()라는 함수도 constructor 안에 추가해보세요.**
➡️
function Student (name, age){
this.name = name;
this.age = age;
this.sayHi: function(){
console.log('안녕 나는' + this.name + '이야')
}
}
var 학생1 = new Student('Kim', 20);
var 학생2 = new Student('Park', 21);
var 학생3 = new Student('Lee', 22);
1. 다음 코드의 출력 결과는 무엇일까요?
function Parent(){
this.name = 'Kim';
}
var a = new Parent();
a.__proto__.name = 'Park';
console.log(a.name)
**➡️ 'Kim'**
첫 4 줄에 의해서 a = {name: 'Kim'}이 되고,
a.__ proto __.name = 'Park'; 이건 **부모 prototype에 {name: 'Park'} 이걸 추가하라는 뜻**이다.
그럼 이제 a.name 이라고 사용했을 때,
**내가 직접 가지고 있는 {name: 'Kim'}** 이걸 우선 출력해준다. (이미 a는 name에 'Kim'을 가지고 있는 상태이기 때문)
2. 함수가 안들어가요 엉엉
위에 0번 문제에서 Student라는 부모에 sayHi라는 함수를 하나 추가하라고 했죠?
그래서 sayHi()라고 사용하면 "안녕 나는 ~~이야" 라고 내 이름을 출력해주는 함수를 prototype에 추가했습니다.
하단처럼 만들었는데 의도한 대로 이름이 출력되지 않고 있습니다.
원인은 무엇일까요?
function Student(이름, 나이){
this.name = 이름;
this.age = 나이;
}
Student.prototype.sayHi = () => {
console.log('안녕 나는 ' + this.name + '이야');
}
var 학생1 = new Student('Kim', 20);
학생1.sayHi(); //왜 이 코드가 제대로 안나오죠?
**➡️화살표 함수로 만들었기 때문에 this.name이 constructor Student의 name이 아니기 때문이다.**
SayHi() 라는 함수를 prototype에 추가할 때 arrow function을 사용했다. 결론부터 말하자면 arrow function은 그냥 일반 function 대체품이 아니다. arrow function은 this 를 바깥에 있는 this를 그대로 사용하고 싶을 때 쓰는 함수라 했다.
암튼 sayHi() 함수를 만들 때 arrow function을 사용해서 내부에 있던 this 값이 이상해진거다.
Student.prototype.sayHi = () => {
console.log(this); // {window}
}
window가 출력된다(strict mode에선 undefined). arrow function은 그냥 바깥 아메두나 있던 값을 가져와서 사용하기 때문이다. Student 함수에서 this는 바깥의 this인 window고, 그 window를 저기 화살표 함수 안에 적용했으니까 this가 window다.
(**object안에 들어있는 함수 안에 있는 this**는 **함수를 부른 object**가 된다)
3. 모든 array에 적용할 수 있는 함수를 직접 새로 만들려면 어떻게 해야할까요?
모든 array에 붙일 수 있는,
array 내에 있는 3이라는 값을 제거해주는 유용한 함수를 하나 만들고 싶습니다.
var arr = [1,2,3];
arr.remove3();
console.log(arr); //[1,2]
이렇게 array뒤에 붙이기만 하면 array 내의 3이라는 모든 숫자 자료들이 삭제됩니다.
멋있게 이름은 remove3() 이라고 하겠습니다.
remove3()함수는 어떻게, 어디에 만들어야 모든 array에 쓸 수 있을까요?
**➡️Array.prototype.remove3 = function(){ ... } 에 만들어야 한다.**
Array.prototype.remove3 = function(){
return this.filter(v => v !== 3)
}
애플코딩 풀이
모든 array 자로형은 부모가 ARray로 부터 new Array() 이런 식으로 만들어지기 때문에 Array라는 부모의 prototype에 있는 pop(), sort(), push(), ... 이런 함수들을 자유롭게 가져다쓸 수 있다.
그러면 우리도 Array의 prototype에 remove3이라는 함수를 하나 추가해주면 된다.
Array.prototype.remove3 = function(){
this 에서 3을 찾아서 제거해주세요
}
구현해보자.
Array.prototype.remove3 = function(){
for (var i = 0; i < this.length; i++) {
if ( this[i] === 3 ) {
this.splice(i,1);
}
}
};
var arr = [1,2,3,4];
arr.remove3();
console.log(arr); //[1,2,4]
'Front-End: Web > JavaScript' 카테고리의 다른 글
[코딩애플] js part 2-5. ES6 방식으로 안쉽게 구현하는 상속기능(Class) (0) | 2022.10.21 |
---|---|
[코딩애플] js part 2-4. 상속기능을 구현하는 다른 방법 (0) | 2022.10.21 |
[코딩애플] js part 2-2. 이상한 Reference data type과 더 이상한 예제 3개 (0) | 2022.10.21 |
[코딩애플] js part 2-1. 자바스크립트 함수 업그레이드하기 (default parameter/arguments) (0) | 2022.10.21 |
[코딩애플] js part 1-7. Spread Operator (...)와 apply / call (0) | 2022.10.09 |