객체와 객체의 상호작용
객체란?
자바스크립트의 객체 : 데이터의 묶음
객체 지향의 객체 : 우리가 표현하고자 하는 사물을 추상적으로 표현한 것
// 나를 객체로 표현
const me = {
// 프로퍼티 (상태)
age : 11,
name : "lee",
address : "서울",
// 메소드 (행동)
canWalk : function() {
console.log("walking");
},
learning : function(teacher) {
console.log("hello");
teacher.feelingUp();
}
}
const teacher = {
feeling : 99,
feelingUp : function() {
this.feeling++;
}
}
me.learning(teacher);
객체는 행동, 상태를 가짐
행동
-> 메소드
상태
-> 프로퍼티
객체와 객체가 서로 메소드를 통해 상호작용 => 객체지향 프로그래밍
new 연산자와 함께 사용하여 객체를 생성
const me = new 생성자함수();
생성자를 통해 생성된 객체들은 같은 프로퍼티, 메소드를 공유할 수 있다.
// 함수 이름은 대문자로 시작
function NewFactory() {
}
let robot1 = new NewFactory();
return 필요없이 new 키워드가 붙으면 자동적으로 객체를 생성하고 반환함
반환된 객체 => 인스턴스라고 부름
function NewFactory(name) {
this.name = name;
this.sayYourName = function() {
console.log(`제 이름은 ${this.name}입니다.`);
}
}
let robot1 = new NewFactory('lee');
생성자 함수 내부의 this
는 생성자가 만들어낸 객체 = 인스턴스
를 참조함
function FoodFactory(foodList) {
this.food = foodList;
const pickFood = foodList[Math.floor(Math.random() * foodList.length)] // 0 ~ length 미만
this.foodName = function() {
console.log(`랜덤 메뉴는 ${pickFood}입니다.`);
}
}
const foodList = ['짜장면','짬뽕','탕수육','냉짬뽕','간짜장'];
let robot3 = new FoodFactory(foodList);
robot3.foodName();
문제 )
객체 생산은 쉽지만 매번 새로운 함수를 생성 => 자원의 낭비
해결 )
프로토타입
- 프로토타입
특정 객체에 대한 참조로 어떠한 공간을 가르킴
생성자 함수가 인스턴스를 생성하면 그 안에는 숨겨진 프로퍼티 [[Prototype]]
이 존재
코드 상으로는 __proto__
로 존재
__proto__
는 자신을 만든 생성자 함수의 prototype
을 참조
결국, 생성자 함수의 prototype
과 인스턴스의 __proto__
연결!!
function Test() {}
const test = new Test();
test.__proto__ === Test.prototype; // true
__proto__
는 오로지 인스턴스에만 존재하며 숨겨진 프로퍼티
prototype
은 오직 function() 안에만 존재하는 참조값
인스턴스는 __proto__
를 통해 생성자 함수의 prototype
에 접근하여 필요한 값, 메서드 사용 가능
모든 인스턴스가 하나의 메서드를 공유하도록 하여 자원 낭비를 막음
자신의 prototype이 없으면 계속 상위로 올라가서 찾는다.
프로토타입 체이닝!!!
function NewFactory2(name) {
this.name = name;
}
NewFactory2.prototype.sayYourName = function() {
console.log(`제 이름은 ${this.name}입니다.`);
}
const robot4 = new NewFactory2('Lee');
const robot5 = new NewFactory2('Kim');
prototype
공간을 하나 가리킴
모든 인스턴스들은 이 공간을 참조하며 이 안에 존재하는 sayYourName()을 사용 가능
prototype
를 통해 메모리 아끼며 모든 메소드 등을 공유 가능
자바스크립트의 상속은 기본적으로 prototype
를 통해 일어난다.
const obj = {
name : 'lee'
}
const arr = [1,2,3]
console.log(arr.hasOwnProperty('name'));
false
가 나오는 이유
Array 함수의 __proto__
가 Object 함수의 prototype
를 참조하고 있기 때문에 Array에서 존재하지 않지만 Object 객체의 프로퍼티와 메서드를 사용할 수 있다.
자기 자신에게 존재하지 않는 프로퍼티나 메소드를 프로토타입
을 통해 추적하는 과정을 프로토타입 체이닝
const str = new String('12345');
str.__proto__
str.__proto__
=== String.prototype
생성자 함수 프로토타입
str.__proto__.__proto__
=== Object.prototype
자바스크립트의 타입들은 기본적으로 Object 타입을 상속 받는다.
function Parent() {
this.name = 'lee'
}
Parent.prototype.rename = function(name) {
this.name = name;
}
Parent.prototype.sayName = function() {
console.log(`제 이름은 ${this.name}입니다.`);
}
function Child() {
Parent.call(this); // Parent()의 프로퍼티 사용
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.canWalk = function() {
console.log('i can walk');
}
const child = new Child();
child.name; // 'lee'
child.rename('kim'); // child.rename에 kim 할당
child.sayName(); // 제 이름은 kim입니다.
Object는 최상위 객체로 아무것도 참조하지 않는다.
Parent.call()에서 call
함수는 Child 함수의 this 가 Parent
생성자 함수의 this를 바라보게 만든다.
즉, Child 통해 생성된 인스턴스 this가 Parent 함수 안의 프로퍼티에 접근 가능
Object.create
함수는 주어진 인자를 Child.prototype
에 연결하는 역할
=> Parent 객체의 프로토타입을 Child 객체의 프로토타입이 참조함
==> Child 객체는 Parent 객체의 모든 것을 상속받게 된다.
1. Parent.call(this);
2. Child.prototype = Object.create(Parent.prototype);
ES6 부터 class 키워드 사용 가능!!
어떠한 사물들의 공통적인 속성을 추상화한 객체
클래스
-> 붕어빵 틀 / 자동차 공장
인스턴스
-> 여러 종류의 붕어빵 / 현0 자동차, 기0 자동차
상위 -> 하위 클래스로 갈수록 상위 클래스를 상속받으면서 더 구체적인
요건이 추가되거나 변경
class 이름 {}
class Robot {
// 클래스의 생성자 함수
// 하나의 클래스는 하나의 생성자만 정의 가능
// 생성자 함수는 new 키워드를 통해 자동 실행
constructor(name) {
this.name = name;
}
// 메소드 정의 (function 키워드 사용 안함)
// 메소드는 클래스가 생성한 인스턴스를 통해 사용 가능
sayYourName() {
console.log(`제 이름은 ${this.name} 입니다.`);
}
}
// 인스턴스 만들기
const robot = new Robot('나난난');
console.log(robot.name); // '나난난'
console.log(robot.sayYourName()); // 제 이름은 나난난 입니다.
자바스크립트의 객체 생성 방법을 다른 언어 클래스 문법처럼 변경된 것이 클래스
더 보기 좋고 편리하게 작성되어 슈가신텍스
라고도 불림
function Me(name, address, phoneNum) {
// 생성자 함수의 this는 인스턴스를 가리킴
this.name = name;
this.address = address;
this.phoneNum = phoneNum; // this.phoneNum은 우리가 전달받는 phoneNum
}
// 메소드 따로 등록
Me.prototype.canWalk = function () {
console.log('내가 걷는다.');
}
Me.prototype.teaching = function (student) {
student.levelUp();
}
const me = new Me('hee','seoul','010');
me.canWalk(); // 내가 걷는다
const me2 = new Me('lee','busan','011');
me2.canWalk(); // 내가 걷는다
function Student(level) {
this.level = level;
}
Student.prototype.levelUp = function() {
this.level++;
}
const student = new Student(1);
me.teaching(student);
위의 코드를 클래스 함수로 변경하기
class Me {
constructor(name, address, phoneNum) {
this.name = name;
this.address = address;
this.phoneNum = phoneNum;
}
canWalk() {
console.log('내가 걷는다.');
}
teaching(student) {
student.levelUp();
}
}
const me = new Me('hee','seoul','010');
me.canWalk(); // 내가 걷는다
const me2 = new Me('lee','busan','011');
me2.canWalk(); // 내가 걷는다
class Student {
constructor(level) {
this.level = level;
}
levelUp() {
this.level++;
}
}
const student = new Student(1);
extends
키워드 사용하여 상속 받음
부모에 존재하는 프로퍼티를 상속받기 위해 super
함수 사용
이때 super
은 부모 생성자를 참조
상속을 받는 클래스 (자식) 파생 클래스
라고 부름
주의
this
를 사용하는 경우 super 함수는 반드시 this 보다 먼저
실행class Robot {
constructor(name) {
this.name = name;
}
sayYourName() {
console.log(`삐리비리. 제 이름은 ${this.name}입니다.`);
}
}
class BabyRobot extends Robot {
constructor(name) {
// super 함수는 this 보다 먼저 실행!!
super(name);
this.ownName = '애기';
}
sayBabyName() {
// extends 상속을 통해 부모 클래스의 메소드 사용 가능
// 때문에 this로 접근 가능!!
this.sayYourName();
console.log('Suceeding you, Father!');
}
}
const 응애1호 = new BabyRobot('응애1호');
응애1호.name; // 응애1호
응애1호.ownName; // 애기
응애1호.sayYourName(); // 삐리비리. 제 이름은 응애1호입니다.
응애1호.sayBabyName();
// 삐리비리. 제 이름은 응애1호입니다.
// Suceeding you, Father!
객체 안의 중요 정보 변경을 막는 역할
#
키워드를 이용하여 프로퍼티를 비공개로 전환
비공개 프로퍼티 값에 접근하고 수정
하려면 => 해당하는 기능을 하는 메서드 사용
class Robot {
#password
constructor(name, pw) {
this.name = name;
this.#password = pw;
}
sayYourName() {}
getPassword() {
return this.#password
}
setPassword(pw) {
this.#password = pw;
}
}
const robot = new Robot('one', '1111');
console.log(robot.name); // one
console.log(robot.getPassword()); // 1111
robot.setPassword('1313');
console.log(robot.getPassword()); // 1313
get
set
키워드를 사용하여 좀 더 단순화하기
class Robot {
#password
constructor(name, pw) {
this.name = name;
this.#password = pw;
}
get Password() {
return this.#password;
}
set Password(pw) {
this.#password = pw;
}
}
const bot = new Robot('one', 1234);
console.log(bot.password); // 1234
// set은 값에 할당하듯이 사용한다.
console.log(bot.password = 1313); // 1313
get, set 키워드를 사용하여 객체의 프로퍼티에 접근하듯 값을 다룬다.
주의할 점 )
마치 객체의 프로퍼티를 수정하는 듯한 착각을 불러일으킨다.
협업자들에게 오해를 일으킬 수 있으므로 주석, 가이드 문서등을 통해 정보를 제공해주어야 한다.
IIFE
함수 - 즉시 실행 함수 표현 (정의되자마자 즉시 실행)const NewPerson = (function(){
let age = 30;
function innerPerson() {}
innerPerson.prototype.getAge = function() {
return age;
}
return innerPerson;
}())
const personWithSecret = new NewPerson();