- 객체 리터럴과 객체
- 클래스와 객체
- 프로퍼티 속성
- 메서드 다형성
- 메서드 추상화
- 상위 클래스 메서드 호출
소스 코드의 고정된 값을 대표하는 용어
예제 코드
const num = 1; // num은 상수이고 1은 10진수 정수 리터럴입니다.
let str = '이름'; // str은 변수이고 '이름'은 문자열 리터럴입니다.
const array = []; // [] = 배열 리터럴.
const object = {}; // {} = 객체 리터럴.
Javascript라는 언어는 거의 대부분이 객체 로 구성되어 있다는 점이다. 따라서 지금 다룰려고하는 프로퍼티가 매우 중요하다.
'Property'는 속성이라는 의미로 간단하게 JS에서는 객체 내부 속성이라고 이해하자
자세한 설명은 3,4장에서 프로퍼티의 속성과 접근자 프로퍼티 등등을 자세하게 소개할 예정이다.
let coffee = {
// name, price는 coffee 고유의 property
name : "Americano",
price : 3000
};
console.log(coffee.name);
// > Americano
JS는 다른 언어와는 다르게 함수 또한 객체로 다루어 지며, 그 중에서도 일급 객체
이므로 값으로 취급 받을 수 있다. 이때 프로퍼티의 값이 함수라면 그 프로퍼티를 우리는 메서드
라고 부른다.
예제코드
const obj = {
f1 : function() {
console.log("hi!");
}
}
obj.f1(); // "hi!"
앞서 우리가 봤던 프로퍼티의 속성은 객체 밖에서도 수정이 가능하였습니다. 하지만 우리는 접근자 프로퍼티를 사용하여 프로퍼티를 객체 밖에서는 수정이 불가능하고 오직 객체 안의 접근자 프로퍼티를 통해서만 가능 하도록 할 수 있습니다.
이를 통해 데이터의 유지보수 및 보안성 이 올라갑니다. (클로저를 사용하면 더욱 보안성이 올라갑니다.)
_
로 시작한다. 예제 코드
const Coffee = () => {
let _name = "Americano"
return {
get name(){
return _name;
},
set name(value){
_name = value;
}
}
}
const coffee = Coffee();
console.log(coffee.name);
// > Americano
console.log(coffee._name)
// > undefined
coffee.name = "Cappuccino"
console.log(coffee.name)
// > Cappuccino
ES6 문법부터 javascript는 생성자 함수(class)를 사용할 수 있게 되었고 사용방법은 다음과 같다.
예제 코드
class Coffee{
constructor(){
this.name = "Americano"
this.price = 1000;
this.amount = 100;
}
drink(){
(this.amount - 20 > 0) ? this.amount -= 20 : this.amount = 0;
}
}
// 인스턴스 생성
const coffee = new Coffee();
coffee.name;
// 객체 생성 후 정의 가능
coffee.temperature = "hot"
객체를 생성하기 위해서는 해당 인스턴스를 생성하고 해당 객체의 프로퍼티 값을 사용할 수 있었다. 하지만 정적 정적 메서드의 경우 인스턴스를 생성하지 않고 사용할 수 있다.
class User {
static staticMethod() {
console.log(this === User);
}
}
User.staticMethod(); // true
이런 특성 때문에 유틸리티 함수 를 만드는데 유용하다.
정적 메서드와 유사한 기능으로 자바스크립트는 정적 프로퍼티도 만들 수 있다. 정적 메서드를 선언할 때와 마찬가지로 static 키워드를 붙여 선언하면 된다. 하지만 비교적 최근에 추가된 스펙이기 때문에 일부 브라우저에서 동작 하지 않을 수 있다.
class User {
static counter = 0;
}
console.log(User.counter); // 0
하지만 이런 정적 메서드와 프로퍼티는 객체 지향적이지 못해 사용을 지양하는 편이다.
- value
- get
- set
- enumerable
- writable
- configurable
Enumberable, Writable, Configurable
이용 가능get & set은 ES6에서부터 나오기 시작한 문법으로 객체의 속성값에 대한 접근 권한자 역할을 할 수 있습니다.
get & set 자체로 writable의 역할을 가지고 있기 때문입니다.
만약 해당 property가 열거 할 수 있는 속성이라면, for ... in... 루프를 사용하여 그것들에 접근할 수 있습니다.
var ob = {a:1, b:2};
ob.c = 3;
Object.defineProperty(ob, 'd', {
value: 4,
enumerable : false
});
// enumerable속성은 조회가능여부와 엄연히 다릅니다.
ob.d; // => 4
// enumerable속성은 열거가능여부와 관련이 있습니다.
for( var key in ob ) console.log( ob[key] );
// Console will print out
// 1, 2, 3
Object.keys( ob ); // => ["a", "b", "c"]
JSON.stringify( ob ); // => "{a:1,b:2,c:3}"
// enumerable속성은 조회가능여부와 엄연히 다릅니다.
ob.d; // => 4
var ob = {a: 1};
Object.defineProperty( ob, 'B', {value: 2, writable:false} );
ob.B = 6; // => 6
ob.B = 1000; // => 1000
// Wriatable속성은 값을 수정하는 것과 관련이 있습니다.
ob.B; // => 2;
function updateB(){
'use strict';
ob.B = 4; // Error
}
updateB(); // Error
구성 가능한 property는 삭제 연산자를 사용하여 제거 할 수 있는지 여부를 의미합니다.
var ob = {};
Object.defineProperty( ob, 'a', {configurable: true, value: 1} );
delete ob.a; // => true
ob; // => {}
Object.defineProperty( ob, 'a', {configurable: false, value: 1} );
delete ob.a; // => false
ob; // => {a:1}
다형성이란 프로그램 언어 각 요소들(상수, 변수, 식, 객체, 메서도 등)이 다양한 자료형(type)에 속하는 것이 허가되는 성질을 가리킨다.
또는 여러 형태를 받아들일 수 있는 성질, 상황에 따라 의미를 다르게 부여할 수 있는 특성이다.
즉, 다형성을 활용하면 기능을 확장하거나, 객체를 변경해야할 때 타입 변경 없이 객체 주입만으로 수정이 일어나게 할 수 있다.
추가적으로, 상속을 사용한다면 중복되는 코드까지 제거할 수 있으므로 객체 지향 설계와 가까워 질 수 있다.
오버로딩은 여러 종류의 타입 혹은 변수들을 받아들여 결국엔 같은 기능을 하도록 만들기 위한 작업이다.
class Print{
constructor(){
this.hi = "hi";
}
printLn(){
console.log(this.hi);
}
printLn(name){
console.log(this.hi + name)
}
}
오버라이딩은 상위 클래스의 메서드를 하위 클래스에서 재정의하는 것을 말한다. 따라서 여기서는 상속의 개념이 추가된다.
class Print{
constructor(){
this.hi = "hi";
}
print(){
console.log(this.hi);
}
}
class Cat extends Print{
constructor(){
super();
this.name = "cat"
}
// 부모 객체의 함수 프로퍼티 재정의
print(){
console.log(this.hi + " " + this.name);
}
}
let cat = new Cat();
cat.print()
// > hi cat
추상 메소드(abstract method)란 자식 클래스에서 반드시 오버라이딩해야만 사용할 수 있는 메소드를 의미합니다.
모듈처럼 중복되는 부분이나 공통적인 부분은 미리 다 만들어진 것을 사용하고, 이를 받아 사용하는 쪽에서는 자신에게 필요한 부분만을 재정의하여 사용함으로써 생산성이 향상되고 배포 등이 쉬워지기 때문입니다.
class Coffee{
constructor(){
this.name = "Coffee"
}
print(){
throw new Error("하위 메서드에서 꼭 해당 함수를 작성해야함")
}
}
class Expresso extends Coffee{
constructor(){
super();
this.name = "Expresso" // 오버라이딩 => 이건 핵심이 아님
}
// print 함수 오버라이딩
print(){
console.log(this.name);
}
}
let expresso = new Expresso();
expresso.print();
// > Expresso