9.1 프로퍼티 나열
1) 배열은 값을 가지며 각 값에는 숫자형 인덱스가 있습니다. 객체는 프로퍼티를 가지며 각 프로퍼티에는 문자열이나 심볼 인덱스가 있습니다 2) 배열에는 순서가 있습니다. 반면 객체는 그런 순서가 보장되지 않습니다.
9.1.1 for…in
1 2 3 4 5 6 7 8 9 10 11 12 const SYM = Symbol ();const o ={a :1 ,b :2 ,c :3 ,[SYM]:4 };for (let prop in o){ if (!o.hasOwnProperty(prop)) continue ; console .log(`${prop} :${o[prop]} ` ) }
hasOwnProperty : for...in에 나타날 위험을 제거하기 위해 사용
for...in 루프에는 키가 심볼인 프로퍼티는 포함 안됌
9.1.2 Object.keys
객체에서 나열 가능한 문자열 프로퍼티를 배열로 반환
1 2 3 4 5 6 7 8 9 10 const SYM = Symbol ();const o ={a :1 ,b :2 ,c :3 ,[SYM]:4 };Object .keys(o).forEach(prop => console .log (`${prop} :${o[prop]} ` ));
hasOwnProperty를 체크할 필요가 없다.
객체의 프로퍼티 키를 배열로 가져와야 할때 Object.keys가 편리하다.
9.2 객체지향 프로그래밍
OOP) 객체 : 데이터와 기능을 논리적으로 묶은 것
클래스 : 자동차처럼 추상적이고 범용적인 것
인스턴스 : 특정 자동차처럼 구체적이고 한정적인 것
메서드 : 기능
클래스 메서드 : 클래스지만 특정 인스턴스에 묶이지 않는 기능
생성자 : 인스턴스를 처음 만들 떄 생성자가 실행됨, 객체 인스턴스를 초기화함
클래스 : 운송수단 서브 클래스 : 자동차, 보트, 비행기.. 보트 서브 클래스 : 요트, 카누,모터보트…
9.2.1 클래스와 인스턴스 생성
ES6애서 클래스를 만드는 간편한 새 문법을 도입함
클래스만들기 1 2 3 4 5 class Car { constructor (){ } }
새 클래스 Car을 만듬, 아직 인스턴스(특정 자동차)는 안만들어짐
인스턴스만들기 1 2 const car1 = new Car();const car2 = new Car();
인스턴스를 만들 떈 new 키워드를 사용한다
instanceof 1 2 3 car1 instanceof Car car1 instanceof Bus
instanceof : 객체가 클래스인지, 인스턴스인지 확인
car1은 Car의 인스턴스이지만, Bus의 인스턴스는 아니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Car { constructor (make, model){ this .make = make; this .model = model; this .userGears = ['P' ,'N' ,'R' ,'D' ]; this .userGear = this .userGears[0 ]; } shift(gear){ if (this .userGears.indexOf(gear)<0 ) throw new Error ('invalid gear :' `${gear} ` ); this .userGear = gear } } const car1 = new Car('Thsla' ,'Model S' );const car2 = new Car('Mazda' ,'3i' );car1.shift('D' ); car2.shift('R' ); car1.userGear
this : 메서드를 호출한 인스턴스를 가리키는 목적
userGears : 사용할 수 있는 기어 목록
gear : 현재 기어 사용할 수 있는 첫번째 기어로 초기화
shift : 메서드(기어변속)
* 실수로 기어 프로퍼티를 고치지 않도록 어느 정도 막을 수 있다.
_ : 외부에서 접근하면 안돼는 프로퍼티 이름 앞에 붙이는 가짜 접근 제한 ex)_userGears
9.2.2 클래스는 함수다.
ES6에서 class 키워드를 도입하기 전까지,클래스를 만드는 것은 곧 클래스 생성자로 사용될 함수를 만든다 는 의미 but, class는 단축 문법일 뿐이고 자바스크립트의 클래스가 바뀐 것은 아님
es5 1 2 3 4 5 6 function Car (make,model ) { this .make = make; this .model = model; this .userGears = ['P' ,'N' ,'R' ,'D' ]; this .userGear = this .userGears[0 ]; }
es6 1 2 3 4 class Es6Car {} function Es5Car {}> typeof Es6Car > typeof Es5Car
9.2.3 프로토타입
프로토타입 메서드: 클래스의 인스턴스에서 사용할 수 있는 메서드 ex) Car.prototype.shift : Car 클래스의 인스턴스에서 사용할 수 있는 shift 메서드는 프로토타입 메서드임
최근엔 메서드를 ‘#’로 표기하기도함 ex)Car#shift
클래스는 대문자로 시작하는게 관용적임
함수의 prototype 프로퍼티가 중요한 시점은 new 키워드로 새 인스턴스를 만들때
new 키워드로 만든 새 객체는 생성자 prototype 프로퍼티에 접근가능
‘proto ‘(밑줄 2개) 프로퍼티에 저장()
동적 디스패치 : 메서드 호출
prototype 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 const Car = (function ( ) { const carProps = new WeakMap (); class Car { constructor (make,model){ this .make = make; this .model = model; this ._userGears = ['P' ,'N' ,'R' ,'D' ]; carProps.set(this ,{userGear :this ._userGears[0 ]}); } get userGear(){return carProps.get(this ).userGear;} set userGear(value){ if (this ._userGears.indexOf(value)<0 ) throw new Error (`${value} ` ); carProps.get(this ).userGear = value; } shift(gear){this .userGear = gear;} } return Car; })(); const car1 = new Car();const car2 = new Car();car1.shift === Car.prototype.shift; car1.shift('D' ); car1.shift('d' ); car1.userGear; car1.shift === car2.shift; car1.shift = function (gear ) {this .userGear = gear.toUpperCase();} car1.shift === Car.prototype.shift;
9.2.4 정적 메서드
정적 메서드 : 클래스 메서드
특정 인스턴스에 적용되지 않음
this는 인스턴스가 아니라 클래스 자체에 묶임
클래스와 관련되지만 인스턴스와 관련없는 범용적 작업에 사용 ex) 자동차 식별 번호 (VIN) 붙이기
여러 인스턴스를 대상으로 하는 작업에도 사용
정적메서드 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 class Car { static getNextVin(){ return Car.nextVin++; } constructor (make,model){ this .make = make; this .model = model; this .vin = Car.getNextVin(); } static areSimilar(car1,car2){ return car1.make == car2.make && car1.model == car2.model; } static areSame(car1,car2){ return car1.vin === car2.vin; } } Car.nextVin = 0 ; const car1 = new Car("Tesla" ,"S" );const car2 = new Car("Mazda" ,"3" );const car3 = new Car("Mazda" ,"3" );car1.vin; car2.vin; car3.vin; Car.areSimilar(car1,car2); Car.areSimilar(car2,car3); Car.areSame(car2,car3); Car.areSame(car2,car2);
9.2.5 상속
클래스 인스턴스는 클래스의 기능을 모두 상속한다.
프로토타입 체인 : 조건에 맞는 프로토타입을 찾을 때 까지 체인을 계속 거슬러감 프로토타입을 찾지 못하면 에러를 일으킴
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 class Vehicle { constructor (){ this .passengers = []; console .log("Vehicle created" ); } addPassenger(p){ this .passengers.push(p); } } class Car extends Vehicle { constructor (){ super (); console .log("Car created" ); } deployAirbags(){ console .log("BWOOSH" ); } } const v = new Vehicle(); v.addPassenger("Frank" ); v.addPassenger("Judy" ); v.passengers; const c = new Car();c.addPassenger("Alice" ); c.addPassenger("Cameron" ); c.passengers; v.deployAirbags(); c.deployAirbags();
extends : Car를 Vehicle의 서브 클래스로 만듬
super() : 슈퍼클래스의 생성자 호출, 서브클래스에서는 이 함수를 반드시 호출
c 에서는 deployAirbags 호출 가능, v 에서는 error
서브클래스는 슈퍼클래스의 모든 메서드에 접근 가능 / 반대는 불가
9.2.6 다형성
다형성 : 여러 슈퍼클러스의 맴버인 인스턴스 instanceOf 연산자: 객체가 클래스의 인스턴스인지 확인
다형성 1 2 3 4 5 6 7 8 9 class Motorcycle extends Vehicle {};const c = new Car();const m = new Motorcycle();c instanceof Car; c instanceof Vehicle; m instanceof Car
자바스크립트의 모든 객체는 루트 클래스인 Object의 인스턴스이다
9.2.7 객체 프로퍼티 나열 다시 보기 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class Super { constructor (){ this .name = 'Super' ; this .isSuper = true ; } } Super.prototype.sneaky = 'not recommended' ; class Sub extends Super { constructor (){ super (); this .name = 'Sub' ; this .isSub = true ; } } const obj = new Sub(); for (let p in obj){ console .log(`${p} : ${obj[p]} ` + (obj.hasOwnProperty(p)? '' : '(inherited)' )); }
9.2.8 문자열 표현
toString : 객채의 기본적인 문자열 표현을 제공
9.3 다중 상속, 믹스인, 인터페이스
다중 상속 : 클래스가 슈퍼 클래스 두 개를 가지는 기능, 충돌 위험 존재인터페이스 : 다중 상속을 지원하지 않는 언어의 경우 인터페이스를 도입믹스인 : 기능을 필요한 만큼 섞은 것Symbol() : 심볼은 고유하므로, 다른 슈퍼클래스의 기능과 충돌할 가능성이 없다.