Open KimHyeSeon opened 4 years ago
6-2 프로토타입 체인 6-2-1 메서드 오버라이드
6-2-2 프로토타입 체인
// 객체 / 배열 내부구조 살펴보기
console.dir({ a:1 });
console.dir([1, 2]);
// 배열 리터럴의 __proto__ 안에 __proto__등장, prototype 객체가 '객체'이기 때문
// 기본적으로 모든 객체의 __proto__ 안에는 object.prototype이 연결됨
6-2-3 객체 전용 메서드의 예외사항
6-1-4 다중 프로토타입 체인
1. 메서드 오버라이드
var Person = function(name) {
this.name = name;
};
Person.prototype.getName = function() {
return this.name;
};
var iu = new Person('지금'); iu.getName = function() { return '바로 ' + this.name; }; console.log(iu.getName()); // 바로 지금
- getName을 찾는 방식은 가장 가까운 대상인 자신의 프로퍼티를 검색하고, 없으면 그 다음으로 가까운 대상인 __proto__를 검색하는 순서로 진행
- __proto__는 검색순서에서 밀려 호출되지 않음
- this가 prototype을 바라보고 있는 것을 인스턴스를 바라볼 수 있도록 call이나 apply를 사용하여 해결가능
console.log(iu.proto.getName.call(iu)); // 바로 지금
**2. 프로토타입 체인**
- 어떤 데이터의 __proto__ 프로퍼티 내부에 다시 __proto__ 프로퍼티가 연쇄적으로 이어진 것
- 이 체인을 따라가며 검색하는 것을 프로토타입 체이닝이라 함
- 자바스크립트 엔진은 데이터 자신의 프로퍼티들을 검색해서 원하는 메서드가 있으면 그 메서드를 실행하고, 없으면 __proto__를 검색해서 있으면 그 메서드를 실행하고, 없으면 다시 __proto__를 검색해서 실행하는 식으로 진행
var arr = [1, 2]; Array.prototype.toString.call(arr); // 1,2 Object.prototype.toString.call(arr); // [object Array] arr.toString(); // 1,2
arr.toString = function() { return this.join('_'); }; arr.toString(); // 1_2
**3. 객체 전용 메서드의 예외사항**
- 어떤 생성자 함수든 prototype은 반드시 객체이기 때문에 Object.prototype이 언제나 프로토타입 체인의 최상단에 존재하게 됨
- 객체에서만 사용할 메서드를 Object.prototype 내부에 정의한다면 다른 데이터 타입에도 해당 메서드를 사용할 수 있게 됨
- Object.prototype에는 어떤 데이터에서도 활용할 수 있는 범용적인 메서드들만 있음
- toString, hasOwnProperty, valueOf, isPrototypeOf 등
**4. 다중 프로토타입 체인**
- 기본 내장 데이터 타입들은 모두 프로토타입 체인이 1단계(객체)이거나 2단계(나머지)로 끝나는 경우만 있었지만, 사용자가 새롭게 만드는 경우는 그 이상 확장 가능
- 대각선의 __proto__를 연결하는 방법은 __proto__가 가리키는 대상, 즉 생성자 함수의 prototype이 연결하고자 하는 상위 생성자 함수의 인스턴스를 바라보게끔 해주면 됨
var Grade = function() { var args = Array.prototype.slice.call(arguments); for (var i = 0; i < args.length; i++) { this[i] = args[i]; } this.length = args.length; }; var g = new Grade(100, 80); // g는 Grade의 인스턴스를 바라봄 //Grade 인스턴스는 배열 형태를 지녔지만, 배열 메서드를 사용할 수 없는 유사배열객체
Grade.prototype = []; //배열 메서드를 사용할 수 있도록 배열의 인스턴스를 바라볼 수 있도록 함
console.log(g); // Grade(2) [100, 80] g.pop(); console.log(g); // Grade(1) [100] g.push(90); console.log(g); // Grade(2) [100, 90]
메서드 위에 메서드를 덮어씌운 것을 메서드 오버라이드라 한다.
var Person = function(name) {
this.name = name;
};
Person.prototype.getName = function() {
return this.name;
}
var iu = new Person('지금');
iu.getName = function() {
return '바로' + this.name;
}
console.log(iu.getName()); //바로 지금
메서드 오버라이딩이 이뤄져 있는 상황에서 prototype에 있는 메서드에 접근 하는 법
console.log(iu.__proto__.getName.call(ui)); //지금
일반 적으로 메서드가 오버라이드된 경우에는 자신으로 부터 가장 가까운 메서드에만 접근할 수 있지만, 그다음으로 가까운 proto 의 메서드도 우회적인 방법을 통해서 접근이 가능하다.
어떤 데이터의 proto 프로퍼티 내부에서 다시 proto 프로퍼티가 연쇄적으로 이어진 것을 프로토타입 체인 이라고 한다.
var arr =[1,2];
Array.prototype.toString.call(arr); // 1,2
Object.prototype.toString.call(arr); // [Object Array]
arr.toString(); // 1,2
arr.toString = function() {
return this.join('_');
}
arr.toString(); // 1,2
prototype은 객체이기 때문에 Object.prototype이 언제나 프로토타입 최상단의 존재. 따라서 객체에서만 사용할 메서드는 다른 여느 데이터 타입에서 프로토타입 객체 안에 정의할 수 없다.
예외적으로 Object.create를 이용하면 Object.prototype 메서드의 접근할 수 엇는 경우
var _proto= Object.create(null);
_proto.getValue = function (key) {
return this[key];
};
var obj = Object.create(_proto);
obj.a = 1;
console.log(obj.getValue('a));
console.dir(obj);
6-2-4 다중 프로토타입 체인
대각 선의 proto를 연결해나가기만 하면 무한대로 체인 관계를 이어나갈 수 있다.
var Grade = function() {
var args = Array.prototype.slice.call(arguments);
for (var i = 0; i < args.length; i++) {
this[i] = args[i]
}
this.length = args.length;
}
var g = new Grade(100, 80);
var Person = function (name) {
this.name = name;
};
Person.prototype.getName = function () {
return this.name;
};
var iu = new Person('지금');
iu.getName = function () {
return + '바로' + this.name;
};
console.log(iu.getName()); //바로 지금
//iu.__protoo__.getName이 아닌 iu 객체에 있는 getName 메서드가 호출됨
// 메서드 오버 드라이브와 프로토타입 체이닝
var = arr = [1, 2];
Array.prototype.toString.call(arr); // 1, 2
Object.prototype.to String.call(arr); // [object, Array]
arr.toString(); // 1, 2
arr toString = function () {
return this.join('_');
};
arr.toString(); // 1_2
//Object.prototype에 추가한 메서드에서의 접근
Object.prototype.getEntries = function() {
var res = [];
for (var prop in this) {
if (this.hasOwnprotoperty(prop)) {
res.push([prop, this[prop]]);
}
}
return res;
};
var date = [
['object', {a:1,b:2, c:3}], // [["a",1],["b",2],["c",3]]
['number', 345],//[]
['string', 'abc'], // [["0","a"],["1","b"],["2","c"]]
['boolean', false], //[]
['func', function () {}], //[]
['array', [1,2,3,4,5]] // array lterator {}
];
data.forEach(function(datum){
console.log(datum[1].getEntries());
});
// Grade 생성자 함수와 인스턴스
var Grade = function () {
var args = Array.prototype.slice.call)arguments);
for (var i = 0; i < args.length; i++) {
this[i] = args[i];
}
this.length = args.length;
};
var g = new Grade(100, 80);
var Person = function(name) {
this.name = name;
};
Person.prototype.getName = function() {
return this.name;
};
var iu = new Person('지금');
iu.getName = function() {
return '바로 ' + this.name;
};
console.log(iu.getName()); // 바로 지금
ㄴ getName이라는 메서드를 찾는 방식은 가장 가까운 대상인 자신의 프로퍼티를 검색하고, 없으면 그 다음으로 가까운 대상인 proto를 검색하는 순서로 진행
console.log(iu.__proto__.getName.call(iu)); // 바로 지금
ㄴ this가 prototype을 바라보고 있는 것을 인스턴스를 바라볼 수 있도록 call이나 apply를 사용하여 해결가능
일반적으로 메서드가 오버라이드된 경우에는 자신으로부터 가장 가까운 메서드에만 접근할 수 있지만, 그 다음으로 가까운 proto의 메서드도 우회적인 방법을 통해 접근 가능
var arr = [1, 2];
Array.prototype.toString.call(arr); // 1,2
Object.prototype.toString.call(arr); // [object Array]
arr.toString(); // 1,2
arr.toString = function() { return this.join('_'); }; arr.toString(); // 1_2
### 3. 객체 전용 메서드의 예외사항
- 어떤 생성자 함수든 prototype은 반드시 객체이기 때문에 Object.prototype이 언제나 프로토타입 체인의 최상단에 존재
- 객체에서만 사용할 메서드를 Object.prototype 내부에 정의한다면 다른 데이터 타입에도 해당 메서드를 사용할 수 있게 됨
- Object.prototype에는 어떤 데이터에서도 활용할 수 있는 범용적인 메서드들만 있음
(toString, hasOwnProperty, valueOf, isPrototypeOf 등)
### 4. 다중 프로토타입 체인
- 기본 내장 데이터 타입들은 모두 프로토타입 체인이 1단계(객체)이거나 2단계(나머지)로 끝나는 경우만 있었지만, 사용자가 새롭게 만드는 경우는 그 이상 확장 가능
- 대각선의 __proto__를 연결해나가기만 하면 무한대로 체인 관계를 이어나갈 수 있음
- 대각선의 __proto__를 연결하는 방법은 __proto__가 가리키는 대상, 즉 생성자 함수의 prototype이 연결하고자 하는 상위 생성자 함수의 인스턴스를 바라보게끔 해주면 됨
```javascript
var Grade = function() {
var args = Array.prototype.slice.call(arguments);
for (var i = 0; i < args.length; i++) {
this[i] = args[i];
}
this.length = args.length;
}; //Grade 인스턴스는 배열 형태를 지녔지만, 배열 메서드를 사용할 수 없는 유사배열객체
var g = new Grade(100, 80); // g는 Grade의 인스턴스를 바라봄
Grade.prototype = []; //배열 메서드를 사용할 수 있도록 배열의 인스턴스를 바라볼 수 있도록 함
console.log(g); // Grade(2) [100, 80]
g.pop();
console.log(g); // Grade(1) [100]
g.push(90);
console.log(g); // Grade(2) [100, 90]
study 완료 후 체크 부탁드립니다.