오늘 배운 내용은 프토토타입과 객체지향 프로그래밍이다. 본 글에서는 객체, 프로토타입 등에 대해서 공부한 내용을 정리하려 한다.
1. 객체란 무엇인가?
- 흔히 '자바스크립트에서는 모든 것이 객체다'라는 말을 하는데, 명백하게 사실과 다른 말이다.
- string, number, boolean, null, undefined와 같은 단순 원시 타입은 객체가 아니다.
- 다만 함수와 배열의 경우에는 '복합 원시 타입'이라는 객체의 하위 타입의 한 종류이다.
# 내장 객체
내장 객체 또한 객체의 하위 타입이다. 이들은 자바스크립트의 타입 중 하나처럼 보이지만 사실은 단지 자바스크립트에 내장된 함수일 뿐이고, 각각 생성자 함수로 사용되어서 주어진 하위 타입의 새로운 객체를 생성하는 역할을 한다.
String
,Number
,Boolean
,Object
,Function
,Array
,Date
,RegExp
,Error
1) 객체와 프로퍼티
- 객체에 값을 보관하면 마치 객체 내부에 프로퍼티 값들이 보관되는 것 같지만 겉보기에만 그렇고 실제로는 그렇지 않다.
- 실제로는 객체 컨테이너에는 각 프로퍼티 값이 있는 곳을 가리키는 포인터로써 역할하는 프로퍼티명이 담겨있게 된다.
- 객체의 프로퍼티명은 언제나 문자열이다. 숫자를 쓰던, 배열을 쓰던 프로퍼티명에는 문자열만 담기게 된다.
2) 객체 복사
- 얕은 복사의 경우 ES6부터 제공되는
Object.assign()
을 이용할 수 있다. (Object.assign MDN) - 다만 얕은 복사는 원시값은 그대로 복사되지만, 참조값은 원래 객체의 레퍼런스와 같은 대상을 가리키는 또 다른 레퍼런스를 만들게 된다.
let array = [], obj = {};
function func () {};
let myObject = {
a: 2,
b: array,
c: obj,
d: func
};
let newObject = Object.assign({}, myObject);
newObject.a; //2
newObject.b === array; // true
newObject.c === obj; // true
newObject.d === func; // true, 원래 레퍼런스와 같은 대상을 가리키는 또 다른 레퍼런스이기 때문에 true이다.
- 깊은 복사는 JSON을 이용할 수 있다.(
let newObject = JSON.parse(JSON.stringify(myObject));
)
3) 프로퍼티 서술자
객체 내의 모든 프로퍼티는 프로퍼티 서술자로 표현이 된다.
let myObject = {
a: 2
};
Object.getOwnPropertyDescriptor(myObject, 'a');
// {
// value: 2,
// writable: true,
// enumerable: true,
// configurable: true
// }
- 만약 프로퍼티 값의 쓰기 가능여부를 조절하고 싶을 경우, writable를 조절한다.
Object.defineProperty(myObject, 'a', {
value: 2,
writable: false, // 쓰기 금지
configurable: true,
enumerable: true
});
myObject.a = 3;
myObject.a; // 2
- 위처럼
writable
속성을 false로 바꾸면, 아래에myObject.a = 3
이라는 코드는 조용히 실패하게 된다. (엄격모드에서는 TypeError가 난다.) - configurable 설정이
true
이면 위처럼defineProperty
를 이용해서 객체의 프로퍼티 서술자를 변경할 수 있다. - 다만 한 번 이를
false
로 변경할 경우 절대 복구되지 않으니 유의해야 한다. - 또한
false
일 경우, 해당 프로퍼티는delete
로 지워지지 않는다. delete
는 삭제 가능한 프로퍼티를 삭제하는 용도로만 사용되고, 만약 특정 객체/함수의 마지막 프로퍼티를 삭제할 경우, 레퍼런스가 삭제되면서 이 객체/함수는 아무것도 참조하지 않기 때문에 가비지 컬렉션의 대상이 된다.- enumerable의 경우, 이 속성을
false
로 바꾸면, 해당 프로퍼티에 접근은 할 수 있지만,for ... in
루프 구문에서는 감춰진다.
4) [[Get]]
let myObject = { a: 2 };
에서myObject.a
로 프로퍼티에 접근할 경우, a란 프로퍼티를 myObject에서 찾지 않는다.- 대신 myObject에 대해서
[[Get]]
연산을 수행한다. 이 연산은 주어진 이름의 프로퍼티를 찾아보고, 있으면 반환하고 없을 경우 다른 작업을 한다.
5) 객체 내의 존재 확인
let myObject = {
a: 2;
};
console.log("a" in myObject); // true
console.log("b" in myObject); // false
myObject.hasOwnProperty("a"); // true
myObject.hasOwnProperty("b"); // false
- 객체 내에 특정 프로퍼티가 존재하는지 확인하는 방법은 2가지 이다.
- 첫번째는
in
연산자를 사용하는 방법이고, 두번째는hasOwnProperty
메소드를 사용하는 것이다. in
연산자는 프로토타입 체인을 통해 해당 객체 내에 프로퍼티가 존재하지 않을 경우, 상위 프로토타입으로 거슬러 올라가서 해당 프로퍼티가 존재하는지까지도 확인한다.- 반면
hasOwnProperty
는 오로지 해당 객체에 프로퍼티가 존재하는지에 대해서만 확인한다. - 객체에서 해당 프로퍼티를 찾지 못할 경우,
undefined
를 리턴한다.
2. 프로토타입
- 자바스크립트의 객체는
[[Prototype]]
이라는 내부 프로퍼티가 존재하고, 다른 객체를 참조하는 레퍼런스로 사용이 된다. - 프로토타입 체인이 연결되면 특정 객체에서 프로퍼티를 찾지 못할 경우, 상위 프로토타입체인으로 거슬러 올라가면서 찾게 되고, 최상위까지 올라갔을 때에도 찾지 못하면
undefined
를 호출한다. - 이는
for ... in
loop에서도 마찬가지로 적용된다. - 모든 함수는
prototype
객체를 가지고 태어나며 모든prototype
객체 내부에는 항상constructor
프로퍼티가 존재한다. 이 둘은 서로가 서로를 가리키는 관계이다. - 생성자 함수 키워드
new
와 함께 함수를 실행할 경우 '생성자 함수'라고 부르는데, 이렇게 생성된 대상을 '인스턴스'라고 부르며 '인스턴스'는 본인을 생성한 생성자 함수 내에 존재하는prototype
객체를 상속받게 된다.
function Func () {};
Func.prototype; // Func 함수 내에 존재하는 prototype 객체.
Func.prototype.constructor; // prototype 객체 내에 존재하는 constructor 프로퍼티. Func를 가리킨다.
const instanceOfFunc = new Func();
// instanceOfFunc는 Func 생성자 함수의 인스턴스이다. Func.prototype을 상속받는다.
3. OOP
객체 지향 프로그래밍의 정의부터 살펴보자.
OOP is a programming paradigm organized around objects rather than actions and logic.
Object can contain related data and code, which represent information about the thing you are trying to model, and functionality or behavior that you want it to have.
만들고자 하는 대상에 대한 속성과 기능을 한 곳에 모아놓은 것이 바로 객체이다.
객체 지향 프로그래밍의 경우 하나의 객체 내에 만들고자 하는 대상과 관련된 모든 내용이 모아져 있다는 측면에서 이해하기 쉽다.
# 은닉화(Encapsultaion)
그런데 자칫 global scope에서 객체를 생성할 경우, 누구나 해당 객체에 대한 접근이 가능하고, 따라서 의도치 않게 해당 객체의 프로퍼티나 메소드가 변경될 수 있다. 이러한 문제를 방지하기 위한 방법 중 하나로 은닉화(캡슐화, Encapsulation)를 하게 되는데, 대표적으로 IIFE(Immediately Invoked Function Expression)을 활용할 수 있다.
IIFE(즉시호출 함수) 내에 객체의 프로퍼티들을 설정할 경우, 해당 객체의 프로퍼티는 global scope가 아닌 익명함수의 scope에 갇히기 때문에 global에서는 해당 프로퍼티에 접근할 수 없다. 단지 IIFE 함수가 return하는 것을 사용하는 것만 가능해진다. 이로써 객체를 더 안전하게 보관할 수 있다. 조금 더 자세한 내용은 이 글에 정리되어 있다.
# 추상화
- 추상화는 복잡한 작동원리는 가리고 단지 이용자가 원하는 결과만을 노출시키는 것을 의미한다.
# Factory 함수
- In JavaScript, any function can return a new object. When it’s not a constructor function or class, it’s called a factory function.
- 즉 생성자 함수나 클래스가 아닌 함수 중 객체를 리턴하는 함수를 factory function이라고 부른다.
# Object.create
Object.create
는 특정 대상 객체(ex. a 객체)에 상속해주길 원하는 객체(ex. b 객체)를 인자로 전달하여, 상속시켜준다.- 예를 들어
const objA = Object.create(objB);
라고 할 경우,objA
는objB
를 상속받는 빈 객체로 할당이 된다.
'Javascript 공부 > TIL' 카테고리의 다른 글
200110(금) : 프로토타입 (0) | 2020.01.10 |
---|---|
200109(목) : 부동소수점, git 경고메세지, 배열 중복 제거 등 (0) | 2020.01.09 |
200106(월) : 비동기, 고차함수, 일급객체, V8 엔진 등 (0) | 2020.01.07 |
191120(수) : response 순서대로 가져오기 등 (0) | 2019.11.20 |
191118(월) : 코딩 인터뷰 완전 분석(1) (0) | 2019.11.18 |
댓글