티스토리 뷰
19장. 프로토타입
- 자바스크립트는 명령형, 함수형, 프로토타입 기반 객체지향 프로그래밍을 지원하는 멀티 패러다임 프로그래밍 언어이다.
- primitive type의 값을 제외한 나머지 값들은 모두 객체이다.
19-1. 객체지향 프로그래밍
- 객체의 집합으로 프로그램을 표현하려는 프로그래밍 패러다임
- 다양한 속성 중에서 프로그램에 필요한 속성만 간추려 내어 표현하는것을 추상화(abstraction)라 한다.
- 속성을 통해 여러 개의 값을 하나의 단위로 구성한 복합적인 자료구조를 객체라 한다.
- 객체는 상태 데이터와 동작을 하나의 논리적인 단위로 묶은 복합적인 자료구조이다.
19-2. 상속과 프로토타입
- 상속(inheritance)는 객체지향 프로그래밍의 핵심 개념으로, 어떤 객체의 프로퍼티 또는 메서드를 다른 객체가 상속받아 그대로 사용할 수 있는 것을 말한다.
// Bad
function Circle(radius) {
this.radius = radius;
this.getArea = function() {
return Math.PI * this.radius ** 2;
}
}
const circle1 = new Circle(1);
const circle2 = new Circle(2);
console.log(circle1.getArea === circle2.getArea); // false
- Circle 생성자는 인스턴스를 생성할 때 마다 동일한 동작을 하는 getArea 메서드를 중복 생성하고 모든 인스턴스가 중복 소유한다.
- 동일한 생성자 함수에 의해 생성된 모든 인스턴스가 동일한 메서드를 중복 소유하는 것은 메모리 낭비이다.
- 인스턴스 생성시마다 메서드를 생성하니 성능에도 악영향을 준다.
// Good
function Circle(radius) {
this.radius = radius;
}
Circle.prototype.getArea = function () {
return Math.PI * this.radius ** 2;
};
const circle1 = new Circle(1);
const circle2 = new Circle(2);
console.log(circle1.getArea === circle2.getArea); // true
- Circle 생성자 함수가 생성한 모든 인스턴스는 자신의 프로토타입, 즉 상위 객체 역할을 하는 Circle.prototype 의 모든 프로퍼티와 메서드를 상속받는다.
19-3. 프로토타입 객체
- 프로토타입 객체란 객체 간 상속을 구현하기 위해 사용된다.
- 프로토타입은 어떤 객체의 상위 객체 역할을 하는 객체로서 다른객체에 공유 프로퍼티를 제공한다.
- 모든 객체는 [[Prototype]] 이라는 내부 슬롯을 가지며, 이 내부 슬롯의 값은 프로토타입의 참조(null인 경우도 있다.)다.
- 객체가 생성될 때 객체 생성 방식에 따라 프로토타입이 결정되고 [[Prototype]]에 저장된다.
- 모든 객체는 하나의 프로토타입을 갖는다.
- 모든 프로토타입은 생성자 함수와 연결되어 있다.
- ex
- 객체 리터럴에 의해 생성된 객체의 프로토타입: Object.prototype
- 생성자 함수에 의해 생성된 객체의 프로토타입: 생성자 함수의 prototype 프로퍼티에 바인딩 되어 있는 객체
__proto__ 접근자 프로퍼티
- 모든 객체는 __proto__ 접근자 프로퍼티를 통해 자신의 프로토타입, 즉 [[Prototype]] 내부 슬롯에 간접적으로 접근할 수 있다.
- 크롬에서 출력해보니 접근자 프로퍼티를 통해 보이지 않고 바로 [[Prototype]] 내부 슬롯을 출력해줌.
- __proto__ 접근자 프로토타입을 통해 프로토타입에 접근하면 내부적으로 __proto__ 접근자 프로퍼티의 getter 함수인 [[Get]] 이 호출된다.
- 새로운 프로퍼티를 할당하면 [[Set]]이 호출된다.
const obj = {};
const parent = { x: 1 };
obj.__proto__; // getter 함수인 get __proto__ 가 호출됨.
obj.__proto__ = parent; // setter 함수인 set __proto__ 가 호출됨.
console.log(obj.x); // 1
- __proto__ 접근자 프로퍼티는 객체가 직접 소유하는 프로퍼티가 아니라 Object.prototype 의 프로퍼티이다.
- 모든 객체는 상속을 통해 Object.prototype.__proto__ 접근자 프로퍼티를 사용할 수 있다.
const person = { name: 'subin' };
console.log(person.hasOwnProperty('__proto__')); // false
console.log(Object.getOwnPropertyDescriptor(Object.prototype, '__proto__'));
// {get: f, set: f, enumerable: false, configurable: true}
console.log({}.__proto__ === Object.prototype); // true
Object.prototype
- 모든 객체는 프로토타입의 계층 구조인 프로토타입 체인에 묶여있다.
- JS 엔진은 객체의 프로퍼티에 접근할 때 접근하려는 프로퍼티가 없다면 __proto__ 접근자 프로퍼티가 가리키는 참조를 따라 부모 역항르 하는 프로토타입의 프로퍼티를 순차적으로 검색한다.
- 프로토타입 체인의 종점, 즉 최상위 객체는 Object.prototype 이며, 이 객체의 프로퍼티와 메서드는 모든 객체에 상속된다.
접근자 프로퍼티를 통해 프로토타입에 접근하는 이유
- 상호 참조에 의해 프로토타입 체인이 생성되는 것을 방지하기 위해서다.
const parent = {};
const child = {};
child.__proto__ = parent;
parent.__proto__ = child; // TypeError: Cyclic __proto__ value
- 프로퍼티 검색 방향이 한쪽 방향으로만 흘러가야 한다.
- 위 예시는 서로가 자신의 프로토타입이 되는 순환 참조 프로토타입 체인을 만들려고 하기에 에러를 발생시킨 다. 그러한 체인을 만들게 된다면 무한루프에 빠진다.
- 따라서 아무 체크 없이 무조건적으로 프로토타입을 교체할 수 없도록 __proto__ 접근자 프로퍼티를 통해 프로토타입에 접근하고 교체하도록 구현되어 있다.
__proto__ 접근자 프로퍼티를 코드내에서 직접 사용하는 것은 권장하지 않는다.
- 모든 객체가 __proto__ 접근자 프로퍼티를 사용할 수 있는 것은 아니다.
- 직접 상속을 통해 Object.prototype 을 상속받지 않는 객체를 생성할 수도 있다.
// 프로토타입 체인의 종점이라서 Object.__proto__ 를 상속받을 수 없음.
const obj = Object.create(null);
console.log(obj.__proto__); // undefined
console.log(Object.getPrototypeOf(obj)); // null
const obj = {};
const parent = { x: 1 };
Object.getPrototypeOf(obj); // obj.__proto__;
Object.setPrototypeOf(obj, parent); // obj.__proto__ = parent;
console.log(obj.x); // 1
- 위와 같은 이유로 아래 메서드 사용을 권장한다.
- 참조를 얻고 싶을 때는 Object.getPrototypeOf()
- 프로토타입 교체하고 싶을 때는 Object.getPrototypeOf()
함수 객체의 prototype 프로퍼티
- 함수 객체만이 소유하는 prototype 프로퍼티는 생성자 함수가 생성할 인스턴스의 프로토타입을 가리킨다.
- non-constructor 인 화살표 함수와 ES6 메서드 축약 표현으로 정의한 메서드는 prototype 프로퍼티 소유하지 않으며, 프로토타입도 생성하지 않는다.
(function () {}).hasOwnProperty('prototype'); // true
// 일반 객체는 prototype 프로퍼티 소유하지 않음.
({}).hasOwnProperty('prototype'); // false
// non-constructor function
const Person = (name) => {
this.name = name;
};
console.log(Person.hasOwnProperty('prototype')); // false
console.log(Person.prototype); // undefined
// non-constructor function
const obj = {
foo() {}
};
console.log(obj.foo.hasOwnProperty('prototype')); // false
console.log(obj.foo.prototype); // undefined
// constructor function
function Person(name) {
this.name = name;
}
const me = new Person('subin');
// 동일한 프로토타입을 가리킨다.
console.log(Person.prototype === me.__proto__); // true
19-4. 리터럴 표기법에 의해 생성된 객체의 생성자 함수와 프로토타입
리터럴 표기 생성자 함수 프로토타입
객체 리터럴 | Object | Object.prototype |
함수 리터럴 | Function | Function.prototype |
배열 리터럴 | Array | Array.prototype |
정규 표현식 리터럴 | RegExp | RegExp.prototype |
const obj = new Object();
console.log(obj.constructor === Object); // true
// ex
const obj2 = {};
console.log(obj2.constructor === Object); // true
- 리터럴 표기법에 의해 생성된 객체도 프로토타입이 존재한다. 하지만 리터럴 표기법에 의해 생성된 객체의 경우 프로토타입의 constructor 프로퍼티가 가리키는 생성자 함수가 반드시 객체를 생성한 생성자 함수라고 단정할 수는 없다.
- 위 예시를 보면 객체 리터럴에 의해 생성된 객체는 Object 생성자 함수로 생성되는게 아닐까? 생각이 든다.
- Object 생성자 함수 명세를 보면 Object 생성자 함수에 인수를 전달하지 않거나 undefined, null 을 인수로 전달하면 내부적으로 Object.prototype 을 프로토타입으로 갖는 빈 객체를 생성한다고 한다.
// Object Constructor function ex
// 1.
let obj = new Object();
console.log(obj); // {}
// 2
class Foo extends Object {}
new Foo(); // Foo {}
// 3
obj = new Object(123);
console.log(obj); // Number {123}
// 4
obj = new Object('123);
console.log(obj); // String {'123'}
- 프로토타입과 생성자 함수는 단독으로 존재할 수 없고 언제나 쌍으로 존재한다.
19-5. 프로토타입의 생성 시점
- 프로토타입은 생성자 함수가 생성되는 시점에 더불어 생성된다.
사용자 정의 생성자 함수와 프로토타입 생성 시점
- 내부 메서드 [[Construct]] 를 갖는 함수 객체, 즉 일반 함수(함수 선언문, 표현식)로 정의한 함수 객체는 new 연산자와 함께 생성자 함수로서 호출할 수 있다.
- constructor는 함수 정의가 평가되어 함수 객체를 생성하는 시점에 프로토타입도 더불어 생성된다.
// constructor 가 평가되어 함수 객체 생성 시점에 프로토타입도 더불어 생성됨.
console.log(Person.prototype); // {constructor: f}
function Person(name) {
this.name = name;
}
- 사용자 정의 생성자 함수는 자신이 평가되어 함수 객체로 생성되는 시점에 프로토타입도 더불어 생성되며, 생성된 프로토타입의 프로토타입은 언제나 Object.prototype 이다.
빌트인 생성자 함수와 프로토타입 생성 시점
- 빌트인 생성자 함수도 일반 함수와 마찬가지로 빌트인 생성자 함수가 생성되는 시점에 프로토타입이 생성된다.
- 모든 빌트인 생성자 함수는 전역 객체가 생성되는 시점에 생성된다.
- 생성자 함수 또는 리터럴 표기법으로 객체를 생성하면 프로토타입은 생성된 객체의 [[Prototype]] 내부 슬롯에 할당된다.
19-6. 객체 생성 방식과 프로토타입의 결정
- 객체의 프로토타입은 추상 연산 OrdinaryObjectCreate 에 전달되는 인수에 의해 결정된다. 이 인수는 객체가 생성되는 시점에 객체 생성 방식에 의해 결정된다.
(https://www.ecma-international.org/ecma-262/11.0/#sec-ordinaryobjectcreate)
객체 리터럴에 의해 생성된 객체의 프로토타입
- JS 엔진이 객체 리터럴을 평가하여 객체를 생성할 때 OrdinaryObjectCreate 를 호출한다. 이때 전달되는 프로토타입은 Object.prototype 이다. 즉, 생성되는 객체의 프로토타입은 Object.prototype 이다.
const obj = { x: 1 };
console.log(obj.constructor === Object); // true
console.log(obj.hasOwnProperty('x')); // true
Object 생성자 함수에 의해 생성된 객체의 프로토타입
- Object 생성자 함수를 호출하면 객체 리터럴과 마찬가지로 OrdinaryObjectCreate 를 호출된다. 이때 전달되는 프로토타입은 Object.prototype 이다.
- 객체 리터럴과의 차이는 프로퍼티를 추가하는 방식이다. 객체 리터럴은 리터럴 내부에 프로퍼티를 추가하지만 Object 생성자 함수 방식은 일단 빈 객체를 생성한 이후 프로퍼티를 추가한다.
const obj = new Object();
obj.x = 1;
console.log(obj.constructor === Object); // true
console.log(obj.hasOwnProperty('x')); // true
생성자 함수에 의해 생성된 객체의 프로토타입
- new 연산자와 함께 생성자 함수를 호출하여 인스턴스를 생성하면 다른 객체 생성 방식과 마찬가지로 OrdinaryObjectCreate 를 호출된다. 이때 전달되는 프로토타입은 생성자 함수의 prototype 프로퍼티에 바인딩 되어있는 객체다.
- Object 생성자 함수와 더불어 생성된 프로토타입 Object.prototype 은 다양한 빌트인 메서드를 가지고 있지만 사용자 정의 생성자 함수로 생성된 프로토타입의 프로퍼티는 constructor 뿐이다.
// 이런식으로 Person.prototype에 프로퍼티를 추가하여 하위 객체가 상속 받을 수 있음.
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
console.log(`hi my name is ${this.name}`);
}
const me = new Person('kingsubin');
me.sayHello(); // hi my name is kingsubin
19-7. 프로토타입 체인
- JS는 객체의 프로퍼티(메서드 포함)에 접근하려고 할 때 해당 객체에 프로퍼티가 없다면 [[Prototype]] 내부 슬롯의 참조를 따라 자신의 부모 프로토타입의 프로퍼티를 순차적으로 검색한다. 이를 프로토타입 체인이라고한다.
- 프로토타입 체인은 상속과 프로퍼티 검색을 위한 메커니즘이다. 이에 반해, 스코프 체인은 식별자 검색을 위한 메커니즘이다.
- 스코프체인과 프로토타입 체인은 서로 협력하여 식별자와 프로퍼티를 검색하는데 사용된다.
- Object.prototype 을 프로토타입 체인의 종점(end of prototype chain)이라 한다.
- Object.prototype 의 프로토타입, 즉 [[Prototype]] 내부 슬롯 값은 null 이다.
- 체인의 종점까지 가서도 프로퍼티를 검색할 수 없으면 에러 발생이 아니라 undefined 를 반환한다.
// ex1
me.hasOwnProperty('name'); // true
// result
Object.prototype.hasOwnProperty.call(me, 'name');
- 위 예시1 에서의 hasOwnProperty 메서드 호출 과정
- me 객체에서 hasOwnProperty 검색
- 없으므로 프로토타입 체인을 따라 Person.prototype 으로 이동하여 hasOwnProperty 검색
- Person.prototype 에도 hasOwnProperty 가 없으므로 프로토타입 체인을 따라 Object.prototype 으로 이동하여 hasOwnProperty 검색
- 발견, JS 엔진은 Object.prototype.hasOwnProperty 를 호출한다. 이때 메서드의 this에는 me 객체가 바인딩된다.
- 위 예시1 에서의 스코프체인 과정
- 스코프 체인에서 me 식별자 검색
- me 식별자는 전역에서 선왼되었으므로 전역 스코프에서 검색
- me 식별자를 검색한 다음, me 객체의 프로토타입 체인에서 hasOwnProperty 검색
19-8. 오버라이딩과 프로퍼티 섀도잉
- 프로토타입 프로퍼티와 같은 이름의 프로퍼티를 인스턴스에 추가하면 프로토타입 프로퍼티를 덮어쓰는 것이 아니라 인스턴스 프로퍼티로 추가한다.
- 인스턴스 메서드 sayHello는 프로토타입 메서드 sayHello를 오버라이딩했고 프로토타입 메서드 sayHello는 가려진다. 이처럼 상속 관계에 의해 프로퍼티가 가려지는 현상을 프로퍼티 섀도잉(property shadowing)이라 한다.
- 프로퍼티 삭제도 마찬가지이다. sayHello 메서드 삭제시 인스턴스 메서드에서 삭제하는 것이지 프로토타입 메서드에서 삭제하는 것이 아니다. 또한 하위 객체를 통해 프로토타입의 set 액세스는 허용되지 않는다.
// 프로토타입의 프로퍼티 변경, 하위 객체를 통해서 못하고 직접 접근 해야함.
// 직접 접근 예시1. 프로토타입 메서드 변경
Person.prototype.sayHello = function() {
console.log(`hey my name is ${this.name}`);
}
me.sayHello(); // hey my name is subin
// 직접 접근 예시2. 프로토타입 메서드 삭제
delete Person.prototype.sayHello;
me.sayHello(); // TypeError: me.sayHello is not a function
19-9. 프로토타입의 교체
생성자 함수에 의한 프로토타입의 교체
const Person = (function () {
function Person(name) {
this.name = name;
}
// 1.
Person.prototype = {
sayHello() {
console.log(`hi my name is ${this.name}`);
}
}
// 2. 프로토타입 교체시 constructor 프로퍼티가 파괴되어 이런 식으로 되살릴 수 있음.
Person.prototype = {
// constructor 프로퍼티와 생성자 함수 간의 연결 설정
constructor: Person,
sayHello() {
console.log(`hi my name is ${this.name}`);
}
}
return Person;
}());
const me = new Person('subin');
- 위 예시를 보면 Person.prototype 에 객체 리터럴을 할당한다. 이는 Person 생성자 함수가 생성할 객체의 프로토타입을 객체 리터럴로 교체한 것이다.
- 교체한 객체 리터럴에는 constructor 프로퍼티가 없다.
- 따라서 me 객체의 생성자 함수를 검색하면 Object가 나온다.
인스턴스에 의한 프로토타입의 교체
- 생성자 함수의 prototype 프로퍼티에 다른 임의 객체를 바인딩 하는것은 미래에 생성할 인스턴스의 프로토타입을 교체하는 것이다.
- __proto__ 접근자 프로퍼티를 통해 프로토타입을 교체하는 것은 이미 생성된 객체의 프로토타입을 교체하는 것이다.
- 생성자함수에 의한 프로토타입의 교체와 마찬가지로 교체한 객체에는 consturctor 프로퍼티가 없으므로 constructor 프로퍼티와 생성자 함수 간의 연결이 파괴된다.
function Person(name) {
this.name = name;
}
const me = new Person('subin');
const parent = {
sayHello() {
console.log(`hi my name is ${this.name}`);
}
};
// 1.
Object.setPrototypeOf(me, parent);
// 2.
me.__proto__ = parent;
// 위의 1, 2 코드는 동일하게 동작함.
me.sayHello(); // hi my name is subin
19-10. instanceof 연산자
- 객체 instanceof 생성자 함수
- 우변의 생성자 함수의 prototype에 바인딩된 객체가 좌변의 객체의 프로토타입 체인 상에 존재하면 true, 아니면 false
- 생성자 함수의 prototype에 바인딩된 객체가 프로토타입 체인 상에 존재하는지 확인한다.
- constructor 프로퍼티와 생성자 함수 간의 연결이 파괴되어도 instanceof 는 영향을 받지 않는다.
function Person(name) {
this.name = name;
}
const me = new Person('subin');
// 1. Person.prototype이 me 객체의 프로토타입 체인에 존재함.
console.log(me instanceof Person); // true
// 2. Object.prototype이 me 객체의 프로토타입 체인에 존재함.
console.log(me instanceof Object); // true
19-11. 직접 상속
Object.create에 의한 직접 상속
- Object.create 는 명시적으로 프로토타입을 지정하여 새로운 객체를 생성한다.
- 장점
- new 연산자 없이 객체 생성 가능
- 프로토타입 지정하면서 객체 생성 가능
- 객체 리터럴에 의해 생성된 객체도 상속 받을 수 있음.
// 1. obj -> null
// 프로토타입이 null인 객체 생성, 프로토타입 체인의 종점에 위치함.
let obj = Object.create(null);
console.log(Object.getPrototypeOf(obj) === null) // true
// 2. obj -> Object.prototype -> null
// obj = {}; 와 동일
obj = Object.create(Object.prototype);
console.log(Object.getPrototypeOf(obj) === Object.prototype) // true
// 3. obj -> Object.prototype -> null
// obj = { x: 1 }; 와 동일
obj = Object.create(Object.prototype, {
x: { value: 1, writable: true, enumerable: true, configurable: true }
});
console.log(Object.getPrototypeOf(obj) === Object.prototype) // true
// 4. obj -> myProto -> Object.prototype -> null
// 임의의 객체를 상속받음.
const myProto = { x: 10 };
obj = Object.create(myProto);
console.log(Object.getPrototypeOf(obj) === myProto) // true
// 5. obj -> Person.prototype -> Object.prototype -> null
// obj = new Person('lee')와 동일
function Person(name) {
this.name = name;
}
obj = Object.create(Person.prototype);
obj.name = 'lee';
console.log(Object.getPrototypeOf(obj) === Person.prototype) // true
- Object.prototype 의 빌트인 메서드는 객체로 직접 호출하지 않는다.
- 왜냐면 Object.create 를 통해 프로토타입 체인 종점에 위치하는 객체를 생성할 수 있고, 그 객체는 Object.prototype 의 빌트인 메서드를 사용할 수 없기 때문이다. 이 같은 에러 발생 위험을 없애기 위해서 간접호출을 사용한다.
let obj = Object.create(null);
obj.a = 1;
console.log(obj.hasOwnProperty('a')); // obj.hasOwnProperty is not a function
console.log(Object.prototype.hasOwnProperty.call(obj, 'a')) // true
객체 리터럴 내부에서 __proto__ 에 의한 직접 상속
const myProto = { x: 10 };
const obj = {
y: 20,
// 직접 상속
// obj -> myProto -> Object.prototype -> null
__proto__: myProto
};
// 위 코드와 동일하다.
const obj = Object.create(myProto, {
y: { value:20, ... }
});
console.log(obj.x, obj.y); // 10 20
console.log(Object.getPrototypeOf(obj) === myProto) // true
19-12. 정적 프로퍼티/메서드
- 정적(static) 프로퍼티/메서드는 생성자 함수로 인스턴스를 생성하지 않아도 참조/호출 할 수 있는 프로퍼티/메서드를 말한다.
- 생성자 함수 객체가 소유한 프로퍼티/메서드를 정적 프로퍼티/메서드라 한다.
- 정적 프로퍼티/메서드는 생성자 함수가 생성한 인스턴스로 참조/호출 할 수 없다.
function Foo() {}
// 프로토타입 메서드
Foo.prototype.x = function () {
console.log('x');
};
// 프로토타입 메서드 호출하려면 인스턴스 생성해야 함.
const foo = new Foo();
foo.x(); // x
// 정적 메서드
Foo.x = function() {
console.log('x');
};
// 인스턴스 생성 없이 호출 가능
Foo.x(); // x
19-13. 프로퍼티 존재 확인
in 연산자, Reflect.has 메서드
- key in object
const person = {
name: 'lee',
address: 'seoul'
};
console.log('name' in person); // true
console.log('name' in person); // true
console.log('age' in person); // false
// 객체가 상속받은 모든 프로토타입의 프로퍼티를 확인함.
// toString은 Object.prototype의 메서드임.
console.log('toString' in person); // true
// Reflect.has 메서드 사용
const person2 = { name: 'lee' };
console.log(Reflect.has(person, 'name')); // true
console.log(Reflect.has(person, 'toString')); // true
Object.prototype.hasOwnProperty 메서드
- 프로퍼티 키가 객체 고유의 프로퍼티 키인 경우에만 true, 상속받은 프로토타입의 키이면 false 반환
console.log(person.hasOwnProperty('name')) // true
console.log(person.hasOwnProperty('age')) // false
console.log(person.hasOwnProperty('toString')) // false
19-14. 프로퍼티 열거
for... in 문
- for (변수선언문 in 객체) { ... }
const person = {
name: 'lee',
address: 'seoul'
};
console.log('toString' in person); // true
for (const key in person) {
console.log(key + ': ' + person[key]);
}
// name: lee
// address: seoul
console.log(Object.getOwnPropertyDescriptor(Object.prototype, 'toString'));
// { ..., enumerable: false }
- 객체의 프로토타입 체인 상에 존재하는 모든 프로토타입의 프로퍼티 중에서 [[Enumerable]] 의 값이 true인 프로퍼티를 순회하며 열거한다.
- toString과 같은 Object.prototype의 프로퍼티가 열거되지 않는다.
- Object.prototype.string 프로퍼티의 [[Enumerable]]의 값이 false이기 때문이다.
- 프로퍼티 키가 심벌인 프로퍼티는 열거하지 않는다.
- for in 문은 프로퍼티 열거시 순서를 보장하지 않는다. 하지만 대부분의 브라우저는 순서를 보장하고 숫자인 프로퍼티 키에 대해서는 정렬을 한다.
- 배열에는 for in 문 사용하지 말고 for 문, for of 문, forEach 메서드 사용을 권장한다.
Object.keys/values/entries 메서드
- 객체 자신의 고유 프로퍼티만 열거하기 위해서는 for in문 보다는 Object.keys/values/entries 메서드 사용을 권장한다.
const person = {
name: 'lee',
address: 'seoul'
__proto__: { age: 20 }
};
// Object.keys
// 객체 자신의 enumerable 프로퍼티 키를 배열로 반환한다.
console.log(Object.keys(person)); // ['name', 'address']
// Object.values
// 객체 자신의 enumerable 프로퍼티 값을 배열로 반환한다.
console.log(Object.values(person)); // ['lee', 'seoul']
// Object.entries
// 객체 자신의 enumerable 프로퍼티 키와 값의 쌍을 배열로 반환한다.
console.log(Object.entries(person)); // [['name', 'lee'], ['address', 'seoul']]
prototype 에 대한 전체적인 부분, 제대로 모르고 그냥 쓰는 메서드들도 익힌듯. 양이 좀 많았군...
반응형
'책 > 모던 자바스크립트 딥다이브' 카테고리의 다른 글
44장. REST API (0) | 2022.05.14 |
---|---|
22장. this (0) | 2022.05.09 |
18장. 함수와 일급 객체 (2) | 2022.04.24 |
17장. 생성자 함수에 의한 객체 생성 (0) | 2022.04.24 |
16장. 프로퍼티 어트리뷰트 (0) | 2022.04.24 |
링크
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
TAG
- 프로그래머스
- 이펙티브자바
- 김영한 JPA
- js api
- HTTP 완벽가이드
- 이펙티브자바 스터디
- dreamcoding
- JS 딥다이브
- Spring Security
- 집 구하기
- 백준
- 드림코딩
- 이펙티브자바 아이템60
- 프로그래머스 SQL
- HTTP 완벽 가이드
- 가상 면접 사례로 배우는 대규모 시스템 설계 기초
- 김영한 http
- js promise
- GCP
- 백기선 스터디
- 이펙티브자바 아이템59
- 모던자바스크립트
- REST API
- 킹수빈닷컴
- BOJ
- java
- JPA 연관관계 매핑
- http
- 패스트캠퍼스 컴퓨터공학 완주반
- js array
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
글 보관함