javaScript/js.ProtoType2

프로토타입(2)

10. 프로토타입의 교체

프로토타입은 다른 임의의 객체로 변경할 수 있다. (부모 객체인 프로토타입을 동적으로 변경할 수 있다는 것을 의미)
이러한 특징을 기반으로 객체 간의 상속 관계를 동적으로 변경할 수 있다.
프로토타입은 생성자 함수 또는 인스턴스에 의해 교체할 수 있다.

10.1 생성자 함수에 의한 프로토타입의 교체

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const Person = (function () {
function Person(name) {
this.name = name;
}

//@생성자 함수의 prototype 프로퍼티를 통해 프로토타입을 교체
//Person 생성자 함수가 생성할 객체의 프로토타입을 객체리터럴로 교체
Person.prototype = {
sayHello() {
console.log(`Hi! My name is ${this.name}`);
}
};
return Person;
}());
const me = new Person('jung');
  • @에서 Person.prototype에 객체 리터럴을 할당.교체
  • 프로토타입으로 교체한 객체 리터럴에는 constructor 프로퍼티가 없다.
  • me 객체의 생성자함수를 검색하면 Person이 아닌 Object가 나온다.
    1
    2
    3
    4
    //프로토타입을 교체하면 constructor 프로퍼티와 생성자 함수 간의 링크가 파괴된다.
    console.log(me.constructor === Person); //false
    //프로토타입 체인을 따라 Object.prototype의 constructor 프로퍼티가 검색된다.
    console.log(me.constructor === Object); //true
  • 프로토타입으로 교체한 객체 리터럴에 constructor 프로퍼티를 추가하면 프로토타입의 constructor 프로퍼티를 되살릴 수 있다.

10.2 인스턴스에 의한 프로토타입의 교체

인스턴스의 proto 접근자 프로퍼티 (or Object.setPrototypeOf메소드)를통해 타입을 교체할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function Person(name) {
tihs.name = name;
}

const me = new Person('jung');

//프로토타입으로 교체할 객체
const parent = {
sayHello() {
console.log(`Hi! My name is ${this.name}`);
}
};
//@ me 객체의 프로토타입을 parent 객체로 교체
Object.setPrototypeof(me, parent);
// me.__proto__ = parent; 위 코드와 동일하게 동작

me.sayHello(); // Hi! My name is jung
  • 생성자 함수로 프로토타입 교체한 것처럼 프로토타입으로 교체한 객체는 constructor가 없다
  • me 객체의 생성자 함수를 검색하면 Person이 아닌 Object가 나온다.

11. instanceof 연산자

  • instanceof 연산자는 이항 연산자로서 좌변에 객체를 가리키는 식별자, 우변에 생성자 함수를 가리키는 식별자를 피연산자로 받는다. 우변의 피연산자가 함수가 아닌 경우 TypeError
  • 좌변의 객체가 우변의 생성자 함수와 연결된 인스턴스라면 true로 평가되고 그렇지 않은 경우 false로 평가된다.
  • instanceof 연산자는 상속관계를 고려한다
1
2
3
4
5
6
7
8
9
function Person(name) {
this.name = name;
}

const me = new Person('jung');

console.log(me instanceof Person); // true
console.log(me instanceof Object); // true
// me 객체는 Object.prototype을 상속받기 때문에 아래의 코드 true
  • instanceof 연산자는 프로토타입의 constructor 프로퍼티가 가리키는 생성자 함수를 찾는 것이 아니라 프로토타입 체인 상에 존재하는 프로토타입에 영향을 받는다.

…..

12. 직접 상속

12.1 Object.create에 의한 직접 상속

Object.create 메소드는 명시적으로 프로토타입을 지정하여 새로운 객체를 생성한다.
Object.create 메소드도 다른 객체생성방식과 마찬가지로 추상연산 ObjectCreate를 호출한다.

  • Object.create 첫번째 매개변수에 생성할 객체의 프로토타입으로 지정할 객체를 전달,
    두번째 매개변수에는 생성할 객체의 프로퍼티를 갖는 객체를 전달한다.

  • 이 객체 형식은 Object.definePropeties 메소드의 두번째 인수와 동일하다.

  • Object.create 메소드는 첫번째 매개변수에 전달한 객체의 프로토타입 체인에 속하는 객체를 생성한다. 객체를 생성하면서 직접적으로 상속을 구현.

    • new 연산자 없이도 객체를 생성할 수 있다.
    • 프로토타입을 지정하면서 객체를 생성할 수 있다. 이때 생성자 함수와 프로토타입 간의 링크가 파괴되지 않는다.
    • 객체 리터럴에 의해 생성된 객체도 특정 객체를 상속받을 수 있다.
  • Object.prototype의 빌트인 메소드는 모든 객체의 프로토타입 체인의 종점인 Object.prototype의 메소드이므로 모든 객체가 상속받아 호출할 수 있다.

1
2
3
4
5
6
7

const obj = { a: 1 };
const child = Object.create(obj);

console.log(obj.hasOwnProperty('a')); // true
console.log(obj.isPrototypeOf(child)); // true
console.log(obj.proertyIsEnumerable('a')); //true

12.2 객체 리터럴 내부에서 proto에 의한 직접 상속

ES6에서는 객체 리터럴 내부에서 proto 접근자 프로퍼티를 사용하여 직접 상속을 구현할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
const myProto = { x: 10 };

//객체 리터럴에 의해 객체를 생성하면서 프로토타입을 지정하여 직접 상속받을 수 있다.
const obj = {
y: 20,
__proto__: myProto
// obj -> myProto -> Object.prototype -> null
};
// const obj = Object.create(myProto, { y: { value: 20} }); 위와 동일

console.log(obj.x obj.y); // 10 20
console.log(Object.getPrototypeOf(obj) === myProto); //true

13. 정적 프로퍼티/메소드

정적(static) 프로퍼티, 메소드는 생성자 함수로 인스턴스를 생성하지 않아도 참조, 호출할 수 있는 프로퍼티, 메소드를 말한다.

14. 프로퍼티 존재 확인

in 연산자는 객체 내에 프로퍼티가 존재하는지 여부를 확인한다.
key : 프로퍼티 키를 나타내는 문자열
object: 객체로 평가되는 표현식
key in object

1
2
3
4
5
6
7
8
9
10
11
const person = {
name: 'jung'
address: 'gimpo'
};

//person 객체에 name 프로퍼티가 존재한다.
console.log('name' in person); // true
//person 객체에 address 프로퍼티가 존재한다.
console.log('adress' in person); //true
//person 객체에 age 프로퍼티가 존재하지 않는다.
console.log('age' in person); //false

in 연산자는 확인 대상 객체(person객체)의 프로퍼티 뿐만 아니라 확인 대상 객체가 상속받은 모든 프로토타입의 프로퍼티를 확인하므로 주의.

1
2
console.log('toString' in person); //true
//person 객체에는 toString이라는 프로퍼티가 없지만 true

in 연산자가 person 객체가 속한 프로토타입 체인 상에 존재하는 모든 프로토타입에서 toString 프로퍼티를 검색했기 때문이다. toString은 Object.prototype의 메소드

  • Object.prototype.hasOwnProperty메소드는 객체 고유의 프로퍼티인 경우에만 true
    상속받은 프로토타입의 프로퍼티인 경우 false를 반환

15. 프로퍼티 열거

15.1 for…in 문

객체의 모든 프로퍼티를 순회하며 열거하려면 for…in문을 사용한다.

for (변수선언문 in 객체) {…}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const person = {
name: 'jung'
address: 'gimpo'
};
//for ...in 문의 변수 prop에 person 객체의 프로퍼티 키가 할당된다.
//순서는 보장되지 않는다.

for (const key in person) {
console.log(key + ': ' + person[key]);
}
// name: jung
// address: gimpo

//2개의 프로퍼티가 있으므로 객체를 2번 순회하면서 프로퍼티 키를 key 변수에 할당한 후 코드블록을 실행한다.
  • for…in 문은 객체의 프로퍼티 개수만큼 반복
  • in 연산자처럼 순회 대상 객체의 프로퍼티 뿐만 아니라 상속받은 프로토타입의 프로퍼티까지 열거
  • 배열에는 for…in문을 사용하지 말고 일반적인 for문이나 for…of문 또는
    Array.prototype.forEach메소드를 사용하기를 권장
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const arr [1, 2, 3];
arr.x = 10; // 배열도 객체이므로 프로퍼티를 가질 수 있다.

for (const i in arr) {
console.log(arr[i]); //프로퍼티 x도 출력. 1 2 3 10
};

//arr.length는 3
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]); //1 2 3
}

//forEach 메소드는 요소가 아닌 프로퍼티는 제외한다.
arr.forEach( v => console.log(v)); //1 2 3

//for...of는 변수 선언문에서 선언한 변수에 키가 아닌 값을 할당한다.
for (const value of arr) {
console.log(value); //1 2 3
};

15.2 Object.keys/values/entries 메소드

  • 객체 자신의 프로퍼티만을 열거하기 위해서는 for…in문을 사용하는 것보다
  • Object.keys/values/entries 메소드를 사용하는 것을 권장한다.
  • Object.keys 메소드는 객체 자신의 열거 가능한 프로퍼티 키를 배열로 반환한다.
1
2
3
4
5
6
7
const person = {
name: 'jung'
address: 'gimpo'
__proto__: { age: 20 }
};

console.log(Object.keys(person)); // ['name', 'address']

ES8에서 도입된 Object.values 메소드는 객체 자신의 열거 가능한 프로퍼티 값을 배열로 반환한다.

1
console.log(Object.values(person));  //['jung', 'gimpo']

ES8에서 도입된 Object.entries 메소드는 객체 자신의 열거 가능한 프로퍼티 키와 값의 쌍의 배열을 배열에 담아 반환한다.

1
2
console.log(Object.entries(person));  
//[['name', 'jung'], ['address', 'gimpo']]
You forgot to set the qrcode for Alipay. Please set it in _config.yml.
You forgot to set the qrcode for Wechat. Please set it in _config.yml.
You forgot to set the business and currency_code for Paypal. Please set it in _config.yml.
You forgot to set the url Patreon. Please set it in _config.yml.
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×