자바스크립트는 프로토타입 기반 언어이다.
- 클래스 기반 언어: 상속을 사용
- 프로토타입 기반 언어: 어떤 객체(prototype)을 원형으로 삼고 이를 복제(참조) → 상속과 비슷한 효과
var instace = new Constructor;
메서드
저장var Person = function (name) {
this._name = name;
}
Person.prototype.getName = function(){
return this._name;
}
// Person 생성자를 이용해 만든 인스턴스는 getName을 호출할 수 있다.
const jinsang = new Person(‘Jinsang’);
jinsang.__proto__.getName(); //undefined
// 이 코드에서 에러가 아닌 undefined가 나왔다는 것은 해당 함수가 호출할 수 있는 함수라는 것을 의미 그러나 왜 undefined 뜰까?
// => this 규칙에따라 어떤 함수를 메서드로서 호출할 때는 메서드 명 바로 앞에 객체인 jinsang.__proto__가 this가 되는데, 이는 Person.prototype을 가리키고 있기 때문에 Person에 _name이지정되지 않았기 때문이다.
jinsang.getName();// “Jinsang”
// 이렇게하면 정상동작하는데, __proto__는 생략 가능하도록 언어가 설계되어있다.
__proto__
는 Constructor의 prototype을 참조한다. -> instance는 __proto__
를 생략할 수 있는 특징 덕에 자신의 것처럼 메서드나 프로퍼티에 접근할 수 있다.var Constructor = function (name) {
this.name = name;
}
Constructor.prototype.method1 = function() {};
Constructor.prototype.property1 = ‘Constuctor prototype property’;
var instance = new Constructor(’Instance’);
console.dir(Constructor);
console.dir(instance);
크롬 개발자 도구의 콘솔에서 확인한 코드 출력결과
var arr1 = new Array();
var arr2 = [];
arr1.forEach(() => {}); // (O)
arr2.from({length: 11}, () => 0); //TypeError: arr2.from is not a function
constructor 프로퍼티는 생성자 함수를 가리킨다.
var arr = [1, 2];
Array.prototype.constructor === Array; //true
arr.__proto__.constructor === Array; //true
arr.constructor === Array; //true
var arr2 = new arr.constructor(3, 4);
console.log(arr2); // [3, 4]
Q. 인스턴스의 생성자 정보를 알아내기 위해 constructor에 의존하는 게 위험한 이유
A. constructor는 읽기 전용 속성이 부여된 예외적인 경우(기본형 리터럴 변수 - number, string, boolean)를 제외하면 값을 바꿀 수 있기 때문이다.
var NewConstructor = function(){
}
1.constructor = NewConstructor();
console.log(1.constructor, 1 instanceof Newconstructor) // Number false
const num = new Number();
console.log(num.constructor, num instanceof Newconstructor) // NewConstructor false
다음은 모두 constructor를 가리킵니다.
[Constructor]
[instance].__proto__.constructor
[instance].constructor
Object.getPrototypeOf([instance]).constructor
[Constructor].prototype.constructor
다음은 모두 prototype을 가리킵니다.
[Constructor].prototype
[instance].__proto__
[instance]
Object.getPrototypeOf([instance])
덮어씌우는
것을 의미한다.var Animal = function(name){
this.name = name;
}
Animal.prototype.getName = function() {
return this.name;
}
var otter = new Animal(’otter’);
otter.getName = function(){
return ‘브라질 ’ + this.name;
}
console.log(otter.getname()); // 브라질 수달
console.log(otter.__proto__.getName()); // undefined
// Animal에 name이 정의되어 있지 않다.
Animal.prototype.name = ‘동물‘;
console.log(otter.__proto__.getName()); // 동물
console.log(otter.__proto__.getName.call(otter)); // 수달
console.dir({ a: 1 });
*__proto__
안에* __proto__
가 있다.__proto__
에는 Object.prototype이 연결된다.
__proto__
는 생략이 가능하다. 그래서 Array가 Object.prototype 내부의 메서드도 자신의 메서드도 자신의 것처럼 호출 가능하다.var arr = [1, 2];
arr(.__proto__).push(3);
arr(.__proto__)(.__proto__).hasOwnProperty(2); // true;
__proto__
프로퍼티 내부에 다시 __proto__
프로퍼티가 연쇄적으로 이어진 것을 프로토타입 체인이라고 한다. 그리고 그 체인을 따라 검색하는 것을 프로토타입 체이닝이라고 한다.
__proto__
가 빈 객체 만들기'프로토타입 체인상 가장 마지막에는 Object.prototype이 있다.'고 했는데, Object.create(null)은 __proto__
가 없는 객체를 생성한다. -> 이를 통해 기본 기능에 제약이 있지만, 객체의 무게가 가벼워져 성능상 이점이 있다.
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.log(obj)
Object.create()
The
Object.create()
static method creates a new object, using an existing object as the prototype of the newly created object.
기존에 존재하는 객체를 새로 생성할 객체의 프로토타입으로 사용함.
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.__proto__
즉, Grade.prototype
이 배열의 인스턴스를 바라보게 하면 된다.Grade.prototype = [];
g.pop() // [100];
g.push(90) // [100, 90]
__proto__
라는, Constructor의 prototype을 참조하는 프로퍼티가 자동으로 부여된다.__proto__
는 언어 설계상 생략 가능한 속성이라, 인스턴스가 Constructor.prototype을 마치 자신의 메서드 인 것처럼 사용 가능하다.arr1.push(100)
__proto__
를 계속 찾아가면 최종적으로 Object.prototype에 당도한다.