// 1
var card = { suit: "하트", rank: "A" };
// 2
function Card(suit, rank){
this.suit = suit;
this.rank = rank;
}
// 3
var card = Object.create(Object.prototype,{
suit: {
value: "하트",
writable: true,
enumerable: true,
configurable: true
},
rank{
value: "A",
writable: true,
enumerable: true,
configurable: true
}
});
생성자 안에서 this 뒤에 메서드를 정의하면 그 생성자로 생성한 모든 인스턴스에 똑같은 메서드가 추가된다. 메서드를 포함한 생성자로 인스턴스를 여러 개 생성하면 같은 작업을 하는 메서드를 인스턴스 개수만큼 생성하게 되며 결과적으로 그만큼 메모리를 소비하게 된다.
→ 프로토타입 객체에 메서드를 정의하는 방식으로 해결
function Circle(center, radius){
this.center = center;
this.radius = radius;
this.area = function(){
return Math.PI*this.radius*this.radius;
};
}
var c1 = new Circle({x:0, y:0}, 2.0);
var c2 = new Circle({x:0, y:1}, 3.0);
var c3 = new Circle({x:1, y:0}, 1.0);
함수의 prototype 프로퍼티가 가르키는 객체를 그 함수의 프로토타입 객체라 한다.
prototype 프로퍼티는 기본적으로 빈 객체를 가르킨다.
function F(){};
console.log(F.prototype); // Object {}

프로토타입 객체의 프로퍼티는 생성자로 생성한 인스턴스에서 그 인스턴스의 프로퍼티처럼 사용할 수 있다. (상속)
프로토타입 객체의 프로퍼티는 읽기만 가능하고 수정이 불가능하다.
F.prototype.prop = "prototype value";
var obj = new F();
console.log(obj.prop); // prototype value
obj.prop = "instance value";
console.log(obj.prop); // instance value
console.log(F.prototype.prop); // prototype value
모든 객체는 내부 프로퍼티 [[Prototype]]을 가지고 있다.
ES6부터는 __proto__프로퍼티에 [[Prototype]]의 값이 저장된다.
var obj = {};
console.log(obj.__proto__); // Object {}
✔️ 객체의 __proto__ 프로퍼티는 그 객체에게 상속을 해 준 부모 객체를 가리킨다.
✔️ 객체는 __proto__ 프로퍼티가 가리키는 부모 객체의 프로퍼티를 사용할 수 있다.
* 실제 프로그래밍할 때는 __proto__ 프로퍼티 값을 직접 입력해서 상속하지 않는다.
var objA = {
name: "Tom",
sayHello: function(){console.log("Hello! "+this.name);}
};
var objB = {
name: "Huck"
};
objB.__proto__ = objA;
var objC = {};
objC.__proto__ = objB;
objC.sayHello(); // "Hello! Huck"
일반적인 프로토타입 상속
객체의 프로토타입은 Object.getPrototypeOf 메서드로 가져올 수 있다.
ES6부터 Object.setPrototypeOf 메서드를 이용해 객체의 프로토타입을 설정할 수 있다.
function F(){}
var obj = new F();
console.log(Object.getPrototypeOf(obj)); // Object{}
?????
지정한 객체의 프로토타입 체인에 지정한 생성자의 프로토타입 객체가 포함되어 있는지 판정한다. 논리값을 반환하는 이항연산자이다.
객체 instanceof 생성자
function F(){};
var obj = new F();
console.log(obj instanceof F); // true
console.log(obj instanceof Object); // true
console.log(obj instanceof Date); //false
instanceof 연산자가 확인하는 것은 그 인스턴스가 해당 생성자로 생성되었는지 여부가 아니라 인스턴스가 생성자의 프로토타입 객체를 상속받았는지 확인한다.
isPrototypeOf 메서드는 특정 객체가 다른 객체의 프로토타입 체인에 포함되어 있는지 판정한다.
프로토타입객체.isPrototype(객체)
function F(){};
var obj = new F();
console.log(F.prototype.isPrototypeOf(obj)); // true
console.log(Object.prototype.isPrototypeOf(obj)); // true
console.log(Date.prototype.isPrototypeOf(obj)); // false
Object.prototype의 메서드는 모든 내장 객체로 전파되며 모든 인스턴스에서 사용할 수 있다.
| 메서드 이름 | 설명 |
|---|---|
| hasOwnProperty(key) | 호출한 객체가 문자열 key를 이름으로 가진 프로퍼티를 소유하는지 뜻하는 논리값으로 반환한다. |
| isPrototypeOf(obj) | 호출한 객체가 인수 obj에 지정한 객체의 프로토타입인지를 뜻하는 논리값을 반환한다. |
| propertyIs Enumerable(key) | 호출한 객체가 문자열 key를 이름으로 가진 프로퍼티를 열거할 수 있는지를 뜻하는 논리값을 반환한다. 이 메서드를 호출한 객체가 소유한 프로퍼티만 판정하며 프로토타입의 프로퍼티는 판정하지 않는다. |
| toLocalString() | toString 메서드와 같다. |
| valueOf() | 호출한 객체의 원시값을 반환한다. |
✔️ 접근자란 객체 지향 프로그래밍에서 객체가 가진 프로퍼티 값을 객체 바깥에서 읽거나 쓸 수 있도록 제공하는 메서드
✔️ 데이터를 부적절하게 변경하는 것을 막고 특정 데이터를 외부로부터 숨길 수 있고 외부에서 데이터를 읽으려고 시도할 때 적절한 값으로 가공해 넘길 수 있다.
✔️ delete 연산자로 삭제할 수 있다.
// getter, setter 함수 예제
var person = {
_name: "Tom",
get name(){
return this._name;
},
set name(value){
var str = value.charAt(0).toUpperCase()+value.substring(1);
this._name = str;
}
};
console.log(person.name); // Tom
person.name = "huck"; // 접근자 프로티에 값을 대입한다.
console.log(person.name) // Huck
// 삭제시 delete 연산자 사용
delete person.name;
접근자 프로퍼티를 이용해 데이터 프로퍼티를 직접 읽고 쓸 수 있다.
즉시 실행 함수로 클로저를 생성하면 데이터를 객체 외부에서 읽고 쓸 수 없도록 숨기고 접근자 프로퍼티만 읽고 쓰도록 만들 수 있다.
var person = (function(){
var _name = "Tom"; // 프라이빗 함수
return{
get name(){
return _name;
},
set name(value){
var str = value.charAt(0).toUpperCase() + value.substring(1);
_name = str;
}
};
})();
console.log(person.name); // Tom
person.name = "huck"; // 접근자 프로퍼티에 값을 대입한다.
console.log(person.name); // Huck
// 변수 _name은 즉시 실행 함수의 지역 변수이므로 함수 바깥에서 읽거나 쓸 수 없다.
쓰기 가능 (writable)
프로퍼티에 쓰기가 가능한지 뜻하는 속성
속성값이 true면 프로퍼티 값을 수정할 수 있다.
열거 가능 (enumerable)
프로퍼티가 for/in 문이나 Object.keys 등의 반복문으로 찾을 수 있는 대상인지를 (열거 가능) 뜻하는 속성
재정의 가능 (configurable)
프로퍼티의 내부 속성을 수정할 수 있는지 뜻하는 속성
속성값이 true면 delete 연산자로 그 프로퍼티를 제거할 수 있으며 프로퍼티가 가진 내부 속성을 수정할 수 있다.
프로퍼티 디스크립터는 프로퍼티의 속성 값을 뜻하는 객체이다.
객체가 가진 프로퍼티 이름은 프로퍼티가 가진 속성 이름과 같다.
// 데이터 프로퍼티의 프로퍼티 디스크립터
{
value: 프로퍼티의 값,
writable: 논리값,
enumerable: 논리값,
configurable: 논리값
}
// 접근자 프로퍼티의 프로퍼티 디스크립터
{
get: getter함수값,
set: setter함수값,
enumerable: 논리값,
configurable: 논리값
}
// 첫 번째 인수는 객체의 참조고 두 번째 인수는 프로퍼티의 이름을 뜻하는 문자열이다.
var tom = { name: "Tom"};
Object.getOwnPropertyDescriptor(tom, "name");
// {value: "Tom", writable: true, enumerable: true, configurable: true}
// 프로토타입으로 상속받은 프로퍼티나 없는 프로퍼티를 지정하면 undefined를 반환한다.
Object.getOwnPropertyDescriptor({}, "name"); // undefined
Object.getOwnPropertyDescriptor(tom, "toString"); // undefined
객체의 프로퍼티에 프로퍼티 디스크립터를 설정한다.
첫 번째 인수: 객체의 참조, 두번째 인수: 프로퍼티의 이름을 뜻하는 문자열,
세 번째 인수: 프로퍼티 디스크립터의 참조
// 실행 후에는 수정한 객체의 참조를 반환한다.
var obj = {};
Object.defineProperty(obj, "name", {
value: "Tom",
writable: ture,
enumerable: false,
configurable: true
});
Object.getOwnPropertyDescriptor(obj, "name");
// {value: "Tom", writable: true, enumerable: false, configurable: true}
객체가 가진 프로퍼티 여러 개에 각각의 프로퍼티 디스크립터를 설정한다.
첫 번째 인수: 객체의 참조, 두 번째 인수: 새롭게 설정, 변경하고자 하는 프로퍼티 이름이 키로 지정된 프로퍼티가 여러 개 모인 객체
실행 후에는 수정된 객체의 참조를 반환한다.
var person = Object.defineProperties({},{
_name: {
value: "Tom",
writable: true,
enumerable: true,
configurable: true
},
name: {
get: function(){ return this._name; },
set: function(value){
var str = value.charAt(0).toUpperCase() + value.substring(1);
this._name = str;
},
enumerable: true,
configurable: true
}
});
Object.getOwnPropertyDescriptor(person, "name");
// {enumerable: true, configurable: true}
객체 안에 지명한 프로퍼티가 있는지 검색하며, 그 검색 대상은 그 객체가 소유한 프로퍼티와 상속받은 프로퍼티 모두이다.
var person = {name : "Tom"};
console.log("name" in person); // true : 이 객체가 소유한 프로퍼티
console.log("age" in person); // false : 프로퍼티가 없음
console.log("toString" in person); // true : person은 toString을 상속받았음
지명한 프로퍼티가 그 객체가 소유한 프로퍼티면 true을 반환하고 상속 받은 프로퍼티면 false를 반환한다.
var person = {name : "Tom"};
console.log(person.hasOwnProperty("name")); // true : 이 객체가 소유한 프로퍼티
console.log(person.hasOwnProperty("toString")); // false : 상속받은 프로퍼티
지정한 프로퍼티가 그 객체가 소유한 프로퍼티이며 열거할 수 있을 때 true 반환
var person1 = {name : "Tom", age: 17}
var person2 = Object.create(person1);
person2.name = "Huck";
console.log(person2.propertyIsEnumerable("name")); // true : 이 객체가 소유한 열거 가능 프로퍼티
console.log(person2.propertyIsEnumerable("age")); // false : 상속받은 프로퍼티
console.log(Object.prototype.propertyIsEnumerable("toString")); // false : 열거할 수 없는 프로퍼티
객체와 객체의 프로토타입 체인에서 열거할 수 있는 프로퍼티를 찾아내어 꺼내는 반복문이다.
Object.prototyped의 프로퍼티는 열거할 수 없으므로 for/in문으로는 찾아낼 수 없다.
var person1 = {name: "Tom", age: 17};
var person2 = Object.create(person1);
person2.name = "Huck";
for(var p in person2) console.log(p); // name, age... 순서대로 표시됨
지정한 객체가 소유한 프로퍼티 중에서 열거할 수 있는 프로퍼티 이름만 배열로 만들어서 반환한다.
해당 객체가 소유한 프로퍼티 이름만 조회하는 용도로 Object.keys 메서드가 적합하다.
var group = {groupName : "Tennis circle"};
var person = Object.create(group);
person.name = "Tom";
person.age = 17;
person.sayHello = function(){console.log("Hello! " + this.name)};
Object.defineProperty(person,"sayHello",{enumerable : false});
console.log(Object.keys(person)); // ["name", "age"]
인수로 지정한 객체가 소유한 프로퍼티 이름을 배열로 만들어서 반환한다.
그때 열거할 수 있는 프로퍼티와 열거할 수 없는 프로퍼티의 이름을 모두 배열로 만든다.
Object.keys 메서드는 열거할 수 없는 프로퍼티인 sayHello는 열거하지 않았지만 getOwnPropertyNames 메서드는 열거할 수 없는 프로퍼티까지 모두 열거한다.
console.log(Object.getOwnPropertyNames(person));
// ["name", "age", "sayHello"]
자바스크립트 객체를 문자열로 표현하는 데이터 포맷이다. JSON을 통해 객체를 직렬화할 수 있다.
직렬화는 컴퓨터의 메모리 속에 있는 객체를 똑같은 객체로 환원할 수 있는 문자열로 변환하는 과정을 말한다.
JSON 포맷은 자바스크립트의 리터럴 표기법에 기반을 두고 있으며 자바스크립트 리터럴 표기법의 부분 집합이다.
JSON 데이터는 그 전체를 작은 따옴표로 묶은 문자열이다.
객체의 프로퍼티 이름은 큰 따옴표로 묶는 문자열로 표기한다.
| 데이터 타입 | 표기 예 | 설명 |
|---|---|---|
| 숫자 | 12.345 | 정수와 부동소수점의 10진수 표기만 가능하다. 부동 소수점은 지수 표기법도 사용할 수 있다. |
| 문자열 | "abc" | 큰따옴표로 묶어야 한다. 이스케이프 시퀀스도 포함할 수 있다. |
| 논리값 | true | true 또는 false |
| null 값 | null | - |
| 배열 | [1, "abc", true] | 모든 데이터 타입을 배열의 요소로 사용할 수 있다. |
| 객체 | {"x": 1 "y": "abc"} | 프로퍼티 이름은 큰 따옴표로 묶는 문자열로 표기한다. |
// 객체 리터럴
{name : "Tom", age: 17, marriage: false, data: [2, 5, null]};
// JSON 데이터로 변환
'{"name" : "Tom", "age" : 17, "marriage": false, "data": [2, 5, null]}'
JSON.stringify(value[, replacer[, space]])
인수로 받은 객체를 JSON 문자열로 바꾸어 반환한다.
첫 번째 인수 : value에는 JSON으로 변환할 객체를 지정한다.
두 번째 인수 : replacer는 함수 또는 배열을 지정한다.
함수를 지정하면 문자열로 만드는 프로퍼티와 키와 값을 함수의 인수로 받아서 프로퍼티 값을 표현하는 문자열을 반환하고 배열을 지정하면 배열의 요소로 객체의 프로퍼티 이름을 필터링한다.
세 번째 인수 : space에는 출력하는 문자열을 구분할 때 사용할 공백 문자를 지정한다.
JSON.stringify({}); // '{}'
JSON.stringify(3.14); // '3.14'
JSON.stringify("abc"); // '"abc"'
JSON.stringify(true); // 'true'
JSON.stringify([2, 4, null]); // '[2, 4, null]'
JSON.stringify({x:1, y:2}); // {"x":1, "y":2}
// 배열로 지정
JSON.stringify({x:1, y:2, z:3}, ["x","z"]); // '{"x":1, "z":3}'
JSON.parse(text[, reviver])
인수로 받은 문자열을 자바스크립트 객체로 환원해서 반환한다.
첫 번째 인수 : text는 자바스크립트의 객체로 환원하고자 하는 JSON 문자열을 지정한다.
두 번째 인수 : 프로퍼티의 키와 값을 인수로 받는 함수를 지정할 수 있다.
// 첫 번째 인수만 지정한 기본 동작
JSON.parse('{}'); //{}
JSON.parse('3.14'); // 3.14
var 0 = {name: "Tom", age: 17, marriage: false, data: [2, 5, null]};
var s = JSON.stringify(o);
// '{"name": "Tom", "age": 17, "marriage": false, "data": [2, 5, null]}'
var p = JSON.parse(s);
// {name: "Tom", age: 17, marriage: false, data: [2, 5, null]}