JavaScript .prototype은 어떻게 작동합니까?


2041

나는 동적 프로그래밍 언어로는 아니지만 JavaScript 코드를 공정하게 작성했습니다. 나는이 프로토 타입 기반 프로그래밍에 대해 전혀 몰두하지 않았다.

var obj = new Object();
obj.prototype.test = function() { alert('Hello?'); };
var obj2 = new obj();
obj2.test();

나는 사람들과 한참 전에 이야기했던 것을 기억합니다. (내가하는 일을 정확히 모르겠습니다) 이해하지만 클래스의 개념은 없습니다. 그것은 단지 객체 일 뿐이며, 그러한 객체의 인스턴스는 원본의 복제품입니다.

그러나 JavaScript에서이 ".prototype"속성의 정확한 목적은 무엇입니까? 객체 인스턴스화와 어떤 관련이 있습니까?

업데이트 : 올바른 방법

var obj = new Object(); // not a functional object
obj.prototype.test = function() { alert('Hello?'); }; // this is wrong!

function MyObject() {} // a first class functional object
MyObject.prototype.test = function() { alert('OK'); } // OK

또한이 슬라이드 는 많은 도움이되었습니다.


78
John Resig는 주제를 살펴볼 때 도움이되는 함수 프로토 타입에 대한 몇 가지 슬라이드를 제공합니다 (코드를 변경하고 어떤 일이 발생하는지 확인할 수 있습니다 ...) http://ejohn.org/apps/learn/#64
John Foster

5
이 질문에 유익한 정보를 제공하기 위해 John 사이트에서 귀하의 사이트가 더 이상 링크를 사용할 수없는 방식으로 변경되는 경우 귀하의 답변에 주석을 달아 두십시오. 어느 쪽이든 +1이 도움이되었습니다.
Chris

95
로 링크 한 존 레식의 자바 스크립트 닌자 # 64를 밀어 넣습니다 . 시작부터 정말 도움이되었고 프로토 타입을 올바르게 이해하고있는 것 같습니다.
유료

4
프로토 타입을 적용하기 위해 실제로 기능적인 객체가 필요합니까? 그렇다면 왜 그렇습니까?
Anshul

6
이 당신을 도울 수 있습니다 webdeveasy.com/javascript-prototype
Naor에게

답변:


1007

모든 자바 스크립트 객체는 내부 "슬롯"이 라고 [[Prototype]]그 값 중 하나 null또는를 object. 슬롯은 JavaScript 코드 내부에있는 객체의 속성으로 작성하는 코드에서 숨겨져 있다고 생각할 수 있습니다. 주위의 대괄호 [[Prototype]]는 의도적이며 내부 슬롯을 나타내는 ECMAScript 사양 규칙입니다.

[[Prototype]]객체가 가리키는 값을 구어체 적으로 "해당 객체의 프로토 타입"이라고합니다.

점 ( obj.propName) 또는 괄호 ( obj['propName']) 표기법을 통해 속성에 액세스 하고 객체에 이러한 속성이없는 경우 (예 :을 통해 확인할 수 있는 자체 속성obj.hasOwnProperty('propName') ) 런타임은 참조 된 객체에서 해당 이름의 속성을 찾습니다. 바이 [[Prototype]]대신. (가) 경우 [[Prototype]] 같은 속성이 없습니다, 그것은 [[Prototype]]다시 확인 등이다. 이런 식으로, 원본 객체의 프로토 타입 체인 은 일치하는 것이 발견되거나 그 끝에 도달 할 때까지 진행됩니다. 프로토 타입 체인의 최상위에는 null가치가 있습니다.

최신 JavaScript 구현 [[Prototype]]은 다음과 같은 방식으로 읽기 및 / 또는 쓰기 액세스를 허용 합니다.

  1. new연산자 (구성하는 생성자 함수로부터 반환 기본 객체 prototype 체인)
  2. extends키워드는, (클래스 구문을 사용하는 경우 프로토 타입 체인을 구성)
  3. Object.create제공된 인수를 [[Prototype]]결과 객체의 결과로 설정합니다.
  4. Object.getPrototypeOfObject.setPrototypeOf( 개체 생성 [[Prototype]] 가져 오기 / 설정 ) 및
  5. 표준화 된 접근 자 (예 : getter / setter) 속성 이름 __proto__(4와 유사)

Object.getPrototypeOf그리고 Object.setPrototypeOf보다 선호하는 __proto__의 행동 때문에 부분적으로 o.__proto__ 드문 객체의 프로토 타입이있는 경우 null.

객체 [[Prototype]]는 초기에 객체 생성 중에 설정됩니다.

를 통해 새 객체를 만들면 기본적으로 new Func()객체의 [[Prototype]]의지는로 참조되는 객체로 설정됩니다 Func.prototype.

따라서 모든 클래스와 new연산자 와 함께 사용할 수있는 모든 함수 에는 .prototype자체 [[Prototype]]내부 슬롯 외에 이름이 지정된 속성이 있습니다. "프로토 타입"이라는 단어의이 이중 사용은 언어를 처음 접하는 사람들 사이에 끝없는 혼란의 근원입니다.

new생성자 함수와 함께 사용하면 JavaScript에서 클래식 상속을 시뮬레이션 할 수 있습니다. 우리가 본 것처럼 JavaScript의 상속 시스템은 프로토 타입이며 클래스 기반이 아닙니다.

JavaScript에 클래스 구문을 도입하기 전에 생성자 함수는 클래스를 시뮬레이션하는 유일한 방법이었습니다. 생성자 함수의 .prototype속성이 참조하는 객체의 속성을 공유 멤버로 생각할 수 있습니다 . 즉. 각 인스턴스에 대해 동일한 멤버 클래스 기반 시스템에서 메소드는 각 인스턴스에 대해 동일한 방식으로 구현되므로 메소드에 개념적으로 .prototype특성이 추가됩니다 . 그러나 객체의 필드는 인스턴스별로 다르므로 생성 중에 객체 자체에 추가됩니다.

클래스 구문이 없으면 개발자는 클래식 상속과 유사한 기능을 달성하기 위해 프로토 타입 체인을 수동으로 구성해야했습니다. 이것은 이것을 달성하기 위해 다른 방법의 우세를 이끌어 냈습니다.

한 가지 방법이 있습니다.

function Child() {}
function Parent() {}
Parent.prototype.inheritedMethod = function () { return 'this is inherited' }

function inherit(child, parent) {
  child.prototype = Object.create(parent.prototype)
  child.prototype.constructor = child
  return child;
}

Child = inherit(Child, Parent)
const o = new Child
console.log(o.inheritedMethod()) // 'this is inherited'

... 그리고 다른 방법이 있습니다 :

function Child() {}
function Parent() {}
Parent.prototype.inheritedMethod = function () { return 'this is inherited' }

function inherit(child, parent) {
    function tmp() {}
    tmp.prototype = parent.prototype
    const proto = new tmp()
    proto.constructor = child
    child.prototype = proto
    return child
}

Child = inherit(Child, Parent)
const o = new Child
console.log(o.inheritedMethod()) // 'this is inherited'

ES2015에 도입 된 클래스 구문 extends은 JavaScript에서 고전적인 상속을 시뮬레이션하기 위해 프로토 타입 체인을 구성하는 "한 가지 진정한 방법" 으로 제공함으로써 사물을 단순화 합니다.

따라서 클래스 구문을 사용하여 다음과 같이 새 객체를 만드는 경우 위의 코드와 유사합니다.

class Parent { inheritedMethod() { return 'this is inherited' } }
class Child extends Parent {}

const o = new Child
console.log(o.inheritedMethod()) // 'this is inherited'

... 결과 개체의이 [[Prototype]]인스턴스로 설정됩니다 Parent, 누구의 [[Prototype]]차례입니다 Parent.prototype.

마지막으로를 통해 새 객체를 만들면 Object.create(foo)결과 객체 [[Prototype]]가로 설정됩니다 foo.


1
그래서 짧은 스 니펫의 프로토 타입 속성에 새로운 속성을 정의하여 잘못된 일을하고 있습니까?
John Leidegren

3
이것이 일급 시민으로서 함수 객체를 갖는 것의 의미라고 생각합니다.
John Leidegren

8
나는 특히 프로그래밍 언어에서 비표준적인 것들을 싫어하는데 왜 명확하게 필요하지 않은 경우 에도 프로토 가 있습니까?
John Leidegren

1
@John __proto__는 JS 인터프리터 만 내부 용으로 필요합니다. 각 Object는 프로토 타입의 일부이고 Object 자체의 일부인 속성과 메서드를 알아야합니다. JS 인터프리터는 오브젝트에서 프로토 타입 된 메소드를 호출 할 수 있어야합니다.
BMiner

17
사용주의 [[프로토 타입]]는 고의적 인 - 이중 대괄호 내부 속성의 ECMA-262은 분리 장치 이름
크리스토프

1798

Java, C # 또는 C ++와 같은 고전적인 상속을 구현하는 언어에서 클래스 (객체에 대한 청사진)를 작성하여 시작한 다음 해당 클래스에서 새 오브젝트를 작성하거나 클래스를 확장하여 확장 할 새 클래스를 정의 할 수 있습니다. 원래 수업.

JavaScript에서는 먼저 객체 개념을 만들지 않고 (클래스 개념이 없음) 자신 만의 객체를 보강하거나 객체를 통해 새로운 객체를 만들 수 있습니다. 어렵지는 않지만 고전적인 방식에 익숙한 사람에게는 약간 외래적이고 신진 대사하기가 어렵습니다.

예:

//Define a functional object to hold persons in JavaScript
var Person = function(name) {
  this.name = name;
};

//Add dynamically to the already defined object a new getter
Person.prototype.getName = function() {
  return this.name;
};

//Create a new object of type Person
var john = new Person("John");

//Try the getter
alert(john.getName());

//If now I modify person, also John gets the updates
Person.prototype.sayMyName = function() {
  alert('Hello, my name is ' + this.getName());
};

//Call the new method on john
john.sayMyName();

지금까지 기본 객체를 확장 해 왔으며 이제 다른 객체를 만든 다음 Person에서 상속했습니다.

//Create a new object of type Customer by defining its constructor. It's not 
//related to Person for now.
var Customer = function(name) {
    this.name = name;
};

//Now I link the objects and to do so, we link the prototype of Customer to 
//a new instance of Person. The prototype is the base that will be used to 
//construct all new instances and also, will modify dynamically all already 
//constructed objects because in JavaScript objects retain a pointer to the 
//prototype
Customer.prototype = new Person();     

//Now I can call the methods of Person on the Customer, let's try, first 
//I need to create a Customer.
var myCustomer = new Customer('Dream Inc.');
myCustomer.sayMyName();

//If I add new methods to Person, they will be added to Customer, but if I
//add new methods to Customer they won't be added to Person. Example:
Customer.prototype.setAmountDue = function(amountDue) {
    this.amountDue = amountDue;
};
Customer.prototype.getAmountDue = function() {
    return this.amountDue;
};

//Let's try:       
myCustomer.setAmountDue(2000);
alert(myCustomer.getAmountDue());

내가 말했듯이 Person에서 setAmountDue (), getAmountDue ()를 호출 할 수는 없습니다.

//The following statement generates an error.
john.setAmountDue(1000);

352
스택 오버 플로우에 대한 답변은 원래 포스터뿐만 아니라 숨어 있거나 검색에서 오는 다른 사람들의 큰 커뮤니티에게도 흥미 롭습니다. 그리고 나는 그들 중 하나였으며 오래된 게시물의 이점을 얻었습니다. 코드 예제를 추가하여 다른 답변에 기여할 수 있다고 생각합니다. 귀하의 질문에 대해 : 당신이 새로운 것을 제외하면 작동하지 않습니다. myCustomer.sayMyName ()을 호출하면 "myCustomer.sayMyName은 함수가 아닙니다"를 반환합니다. 가장 쉬운 방법은 파이어 버그를 실험하고 어떤 일이 일어나는지 확인하는 것입니다.
stivlo

7
내가 이해하는 한 var Person = function (name) {...}; Person Objects를 빌드 할 수있는 생성자 함수를 정의합니다. 따라서 아직 Object가 없으며 익명 생성자 함수 만 Person에 할당됩니다. 이것은 매우 좋은 설명입니다 : helephant.com/2008/08/how-javascript-objects-work
stivlo

17
경고 :이 답변은 부모 클래스 생성자가 인스턴스별로 호출되지 않는다는 사실을 무시합니다. 그것이 작동하는 유일한 이유는 자식 및 부모 생성자 모두에서 똑같은 일을 (이름 설정)했기 때문입니다. JavaScript (및 최종 솔루션)에서 상속을 시도 할 때 발생하는 일반적인 실수에 대한 자세한 내용은 이 스택 오버플로 포스트
Aaren Cordova

3
이 답변에서도 "new Person ()"을 프로토 타입으로 사용함으로써 실제로 "Person"의 "name"인스턴스 속성을 "Customer"의 정적 속성으로 설정한다는 것을 언급하지 않습니다. 인스턴스는 동일한 속성을 갖습니다). 좋은 기본 예이지만 그렇게하지 마십시오. :) 프로토 타입을 "Person.prototype"으로 설정하여 "브리지"로 작동 할 새 익명 함수를 만든 다음 해당 인스턴스에서 인스턴스를 만들고 대신 "Customer.prototype"을 해당 익명 인스턴스로 설정합니다.
James Wilkins

10
[정보 Customer.prototype = new Person();라인, MDN 쇼 예를 들어 사용 Customer.prototype = Object.create(Person.prototype)하고, 국가는 '여기에 일반적인 오류는 "새 사람 ()"를 사용하는 것입니다' . 출처
Rafael Eyng

186

설명없이 샘플로 간주되는 매우 간단한 프로토 타입 기반 객체 모델입니다.

function Person(name){
    this.name = name;
}
Person.prototype.getName = function(){
    console.log(this.name);
}
var person = new Person("George");

프로토 타입 개념을 진행하기 전에 고려해야 할 몇 가지 중요한 사항이 있습니다.

1- JavaScript 함수의 실제 작동 방식 :

첫 번째 단계를 수행하려면 JavaScript 함수가 실제로 어떻게 작동하는지, this키워드 를 키워드로 사용하는 함수와 같은 클래스 또는 인수가있는 일반 함수, 수행하는 작업 및 반환되는 작업으로 파악해야합니다.

Person객체 모델 을 만들고 싶다고 가정 해 봅시다 . 그러나이 단계 에서는 prototypeand newkeyword 를 사용하지 않고 동일한 작업수행 하려고 합니다 .

그래서이 단계에서 functions, objects그리고 this키워드, 우리 모두입니다.

첫 번째 질문이 될 것이다 어떻게 this키워드를 사용하지 않고 유용 할 수 있습니다 new키워드를 .

그래서 대답하기 위해 빈 객체가 있고 두 가지 기능이 있다고 가정 해 봅시다.

var person = {};
function Person(name){  this.name = name;  }

function getName(){
    console.log(this.name);
}

지금은 사용하지 않고 new키워드를 우리는 이러한 기능을 사용할 수있는 방법에 대해 설명합니다. 따라서 JavaScript에는 3 가지 방법이 있습니다.

ㅏ. 첫 번째 방법은 함수를 일반 함수로 호출하는 것입니다.

Person("George");
getName();//would print the "George" in the console

이 경우 이는 현재 컨텍스트 객체이며 일반적으로 window브라우저 또는 의 전역 객체 GLOBAL입니다 Node.js. "George"를 값으로 사용하여 브라우저의 window.name 또는 Node.js의 GLOBAL.name을 갖습니다.

비. 속성으로 객체에 첨부 할 수 있습니다

- 가장 쉬운 방법 은 다음 person과 같이 빈 개체를 수정하는 것입니다.

person.Person = Person;
person.getName = getName;

이런 식으로 우리는 다음과 같이 호출 할 수 있습니다.

person.Person("George");
person.getName();// -->"George"

이제 person객체는 다음과 같습니다.

Object {Person: function, getName: function, name: "George"}

- 속성 을 객체 에 첨부하는 다른 방법prototype 은 이름이 __proto__인 JavaScript 객체에서 찾을 수있는 객체를 사용 하는 것입니다. 요약 부분에서 조금 설명하려고했습니다. 따라서 다음을 수행하여 비슷한 결과를 얻을 수 있습니다.

person.__proto__.Person = Person;
person.__proto__.getName = getName;

그러나 실제로 우리가하고있는 일은 Object.prototype리터럴 ( { ... })을 사용하여 JavaScript 객체를 만들 때마다을 기반으로 만들어 지기 때문에을 수정하는 것 Object.prototype입니다. 즉 새로 작성된 객체에 이름이 지정된 속성으로 첨부 __proto__되므로 변경하면 이전 코드 스 니펫에서 수행했듯이 모든 JavaScript 객체는 변경되지는 않지만 좋은 습관은 아닙니다. 이제 더 나은 방법은 무엇입니까?

person.__proto__ = {
    Person: Person,
    getName: getName
};

그리고 이제 다른 물건들은 평화 롭지 만 여전히 좋은 습관은 아닌 것 같습니다. 따라서 여전히 하나 이상의 솔루션이 있지만이 솔루션을 사용하려면 person객체가 작성된 코드 줄로 돌아가서 var person = {};다음과 같이 변경해야합니다.

var propertiesObject = {
    Person: Person,
    getName: getName
};
var person = Object.create(propertiesObject);

그것이하는 일은 새로운 JavaScript를 만들고 속성에 Object첨부 propertiesObject하는 __proto__것입니다. 그래서 당신이 할 수 있는지 확인하십시오 :

console.log(person.__proto__===propertiesObject); //true

그러나 여기서 까다로운 점 __proto__person객체 의 첫 번째 수준에 정의 된 모든 속성에 액세스 할 수 있다는 것입니다 (자세한 내용은 요약 부분을 읽으십시오).


이 두 가지 방법 중 하나를 사용 this하면 person객체 를 정확하게 가리킬 수 있습니다.

씨. JavaScript에는 함수를 제공하는 또 다른 방법이 있습니다.이 함수 this호출 또는 적용 을 사용 하여 함수를 호출합니다.

apply () 메소드는 주어진이 값과 배열 (또는 배열과 같은 객체)로 제공된 인수로 함수를 호출합니다.

call () 메소드는 주어진이 값과 인수가 개별적으로 제공되는 함수를 호출합니다.

내가 가장 좋아하는 방법으로 다음과 같이 함수를 쉽게 호출 할 수 있습니다.

Person.call(person, "George");

또는

//apply is more useful when params count is not fixed
Person.apply(person, ["George"]);

getName.call(person);   
getName.apply(person);

이 3 가지 방법은 .prototype 기능을 파악하기위한 중요한 초기 단계입니다.


2- new키워드는 어떻게 작동합니까?

이것은 .prototype기능 을 이해하기위한 두 번째 단계입니다. 이것은 프로세스를 시뮬레이션하는 데 사용하는 것입니다.

function Person(name){  this.name = name;  }
my_person_prototype = { getName: function(){ console.log(this.name); } };

이 부분에서는 new키워드 prototype를 사용할 때 키워드 를 사용하지 않고 JavaScript가 취하는 모든 단계를 수행하려고 new합니다. 그래서 우리가 할 때 new Person("George"), Person함수는 생성자 역할을합니다. 이것은 JavaScript가 하나씩하는 것입니다.

ㅏ. 우선 빈 객체, 기본적으로 빈 해시를 만듭니다.

var newObject = {};

비. JavaScript가 취하는 다음 단계 는 모든 프로토 타입 객체를 새로 만든 객체 에 첨부 하는 것입니다.

우리가 my_person_prototype여기에 프로토 타입 객체에 대한 유사.

for(var key in my_person_prototype){
    newObject[key] = my_person_prototype[key];
}

JavaScript가 실제로 프로토 타입에 정의 된 속성을 첨부하는 방식이 아닙니다. 실제 방법은 프로토 타입 체인 개념과 관련이 있습니다.


ㅏ. & b. 이 두 단계 대신 다음을 수행하여 동일한 결과를 얻을 수 있습니다.

var newObject = Object.create(my_person_prototype);
//here you can check out the __proto__ attribute
console.log(newObject.__proto__ === my_person_prototype); //true
//and also check if you have access to your desired properties
console.log(typeof newObject.getName);//"function"

이제 우리는 getName함수를 호출 할 수 있습니다 my_person_prototype:

newObject.getName();

씨. 그런 다음 해당 객체를 생성자에게 제공합니다.

우리는 다음과 같은 샘플로 이것을 할 수 있습니다 :

Person.call(newObject, "George");

또는

Person.apply(newObject, ["George"]);

다음 생성자가 있기 때문에, 원하는 무엇이든 할 수있는 그 생성자의 내부 방금 생성 된 개체입니다.

이제 다른 단계를 시뮬레이션하기 전의 최종 결과 : Object {name : "George"}


요약:

기본적으로 함수 에서 new 키워드 를 사용하면 해당 키워드를 호출하고 해당 함수가 생성자로 사용되므로 다음과 같이 말할 때 :

new FunctionName()

자바 스크립트는 내부적으로 객체, 빈 해시를 만든 다음이 생성자에 그 객체를 제공하고 생성자가 있기 때문에, 원하는 무엇이든 할 수있는 그 생성자의 내부 방금 생성 된 개체이며, 그것은 당신에게 물론 그 객체를 제공합니다 함수에서 return 문을 사용하지 않았거나 return undefined;함수 본문 끝에를 넣은 경우

따라서 JavaScript가 객체에서 속성을 조회 할 때 가장 먼저하는 일은 해당 객체에서 속성을 찾는 것입니다. 그리고 [[prototype]]우리가 일반적으로 좋아 하는 비밀 속성 이 __proto__있으며 그 속성은 JavaScript가 다음에 보는 것입니다. 그리고 __proto__또 다른 JavaScript 객체 인 경우을 통해 볼 때 자체 __proto__속성 이 있으며 다음 속성 __proto__이 null 이 될 때까지 올라갑니다 . 포인트는 JavaScript에서 __proto__속성이 null 인 유일한 객체입니다 Object.prototype.

console.log(Object.prototype.__proto__===null);//true

이것이 JavaScript에서 상속이 작동하는 방식입니다.

프로토 타입 체인

즉, 함수에 프로토 타입 속성이 있고 새로 호출하면 JavaScript가 새로 작성된 속성에 대한 객체를 찾은 후 함수를 살펴보고이 .prototype객체에 해당 객체가있을 수 있습니다. 자체 내부 프로토 타입. 등등.


6
a) 속성을 복사하여 프로토 타입을 설명하지 마십시오. b) 생성자 함수가 인스턴스에 적용되기 전에 내부 [[prototype]]이 발생 하도록 설정하십시오. 순서를 변경하십시오. c) jQuery가이 질문에서 완전히
벗어난 주제

1
@ Bergi : 지적 해 주셔서 감사합니다. 지금 괜찮다면 알려주십시오.
Mehran Hatami 2019

7
간단하게 만들 수 있습니까? 당신은 모든 점에서 옳습니다. 그러나이 설명을 읽는 학생들은 처음으로 혼란 스러울 수 있습니다. 더 간단한 예를 들어서 코드 자체를 설명하거나 의미를 명확하게하기 위해 주석을 추가하십시오.
오후

2
@PM : 의견을 보내 주셔서 감사합니다. 가능한 한 간단하게 만들려고했지만 여전히 모호한 점이 있다고 생각합니다. 그래서 나는 그것을 수정하고 더 설명하려고 노력할 것입니다. :)
Mehran Hatami

1
@AndreaMattioli이 방법으로 완전히 새로운 객체를 만들고 다른 객체와 공유 될 수있는 오래된 객체를 재정의합니다. 교체 __proto__하면 먼저 모든 최상위 프로토 타입 속성을 지우고 공유하지 않는 한 더 이상 공유되지 않는 새로운 프로토베이스를 갖게됩니다.
Mehran Hatami

77

프로토 타입의 7 개 Koans

깊은 명상 후 시로 산이 파이어 폭스 산으로 내려 갔을 때 그의 마음은 깨끗하고 평화로웠다.

그러나 그의 손은 불안했고, 그 자체로 붓을 잡고 다음 음표를 적어 두었다.


0) 두 가지 다른 것을 "시제품"이라고 부를 수 있습니다.

  • 와 같은 프로토 타입 속성 obj.prototype

  • 원형 내부 속성으로 표시 [[Prototype]] ES5에서 .

    ES5를 통해 검색 할 수 있습니다 Object.getPrototypeOf().

    Firefox는 __proto__속성을 통해 확장 기능으로 액세스 할 수 있습니다 . ES6는 이제에 대한 선택적 요구 사항을 언급 합니다 __proto__.


1) 이러한 개념은 질문에 대답하기 위해 존재합니다.

내가 할 때 obj.propertyJS는 어디를 찾는가 .property?

직관적 인 고전 상속은 속성 조회에 영향을 미칩니다.


2)

  • __proto__.에서와 같이 도트 속성 조회에 사용됩니다 obj.property.
  • .prototype를 사용 하여 객체를 생성 할 때 간접적으로 만 직접 조회하는 데 사용 되지 않습니다 .__proto__new

조회 순서는 다음과 같습니다.

  • objobj.p = ...또는로 추가 된 속성Object.defineProperty(obj, ...)
  • 의 속성 obj.__proto__
  • 의 속성 obj.__proto__.__proto__ , 그리고에 이렇게
  • 일부 경우 __proto__입니다 null반환 undefined.

이것이 소위 프로토 타입 체인입니다 입니다.

당신은 피할 수 .와 조회 obj.hasOwnProperty('key')Object.getOwnPropertyNames(f)


3) 두 가지 주요 설정 방법이 있습니다 obj.__proto__.

  • new:

    var F = function() {}
    var f = new F()

    그런 다음 new설정했습니다 :

    f.__proto__ === F.prototype

    이것이.prototype 사용되는 곳 입니다.

  • Object.create:

     f = Object.create(proto)

    세트 :

    f.__proto__ === proto

4) 코드 :

var F = function(i) { this.i = i }
var f = new F(1)

다음 다이어그램에 해당합니다 (일부 Number는 생략).

(Function)       (  F  )                                      (f)----->(1)
 |  ^             | | ^                                        |   i    |
 |  |             | | |                                        |        |
 |  |             | | +-------------------------+              |        |
 |  |constructor  | |                           |              |        |
 |  |             | +--------------+            |              |        |
 |  |             |                |            |              |        |
 |  |             |                |            |              |        |
 |[[Prototype]]   |[[Prototype]]   |prototype   |constructor   |[[Prototype]]
 |  |             |                |            |              |        |
 |  |             |                |            |              |        |
 |  |             |                | +----------+              |        |
 |  |             |                | |                         |        |
 |  |             |                | | +-----------------------+        |
 |  |             |                | | |                                |
 v  |             v                v | v                                |
(Function.prototype)              (F.prototype)                         |
 |                                 |                                    |
 |                                 |                                    |
 |[[Prototype]]                    |[[Prototype]]          [[Prototype]]|
 |                                 |                                    |
 |                                 |                                    |
 | +-------------------------------+                                    |
 | |                                                                    |
 v v                                                                    v
(Object.prototype)                                       (Number.prototype)
 | | ^
 | | |
 | | +---------------------------+
 | |                             |
 | +--------------+              |
 |                |              |
 |                |              |
 |[[Prototype]]   |constructor   |prototype
 |                |              |
 |                |              |
 |                | -------------+
 |                | |
 v                v |
(null)           (Object)

이 다이어그램은 많은 언어 사전 정의 된 오브젝트 노드를 보여줍니다.

  • null
  • Object
  • Object.prototype
  • Function
  • Function.prototype
  • 1
  • Number.prototype( (1).__proto__구문을 만족시키기 위해 필수 인 괄호 로 찾을 수 있음 )

우리의 두 줄의 코드는 다음과 같은 새로운 객체 만 만들었습니다.

  • f
  • F
  • F.prototype

if당신이 할 때 의 속성입니다 :

var f = new F(1)

이 평가 Fthis가치있는 new다음에 할당됩니다 반환됩니다, f.


5) .constructor 일반적으로 조회 를 F.prototype통해 발생합니다 ..

f.constructor === F
!f.hasOwnProperty('constructor')
Object.getPrototypeOf(f) === F.prototype
F.prototype.hasOwnProperty('constructor')
F.prototype.constructor === f.constructor

우리가 작성할 때 f.constructorJavaScript는 다음 .과 같이 조회를 수행합니다.

  • f 이 없습니다 .constructor
  • f.__proto__ === F.prototype가지고 .constructor === F, 가지고

클래식 OOP 언어와 매우 유사한 방식으로 필드 설정 등 을 구성하는 데 사용 f.constructor == F되므로 결과 는 직관적으로 정확 합니다.Ff


6) 프로토 타입 체인을 조작하여 클래식 상속 구문을 얻을 수 있습니다.

ES6는 이전에 가능한 프로토 타입 조작 광기를위한 구문 설탕 인 classand 및 extends키워드를 추가합니다 .

class C {
    constructor(i) {
        this.i = i
    }
    inc() {
        return this.i + 1
    }
}

class D extends C {
    constructor(i) {
        super(i)
    }
    inc2() {
        return this.i + 2
    }
}
// Inheritance syntax works as expected.
c = new C(1)
c.inc() === 2
(new D(1)).inc() === 2
(new D(1)).inc2() === 3
// "Classes" are just function objects.
C.constructor === Function
C.__proto__ === Function.prototype
D.constructor === Function
// D is a function "indirectly" through the chain.
D.__proto__ === C
D.__proto__.__proto__ === Function.prototype
// "extends" sets up the prototype chain so that base class
// lookups will work as expected
var d = new D(1)
d.__proto__ === D.prototype
D.prototype.__proto__ === C.prototype
// This is what `d.inc` actually does.
d.__proto__.__proto__.inc === C.prototype.inc
// Class variables
// No ES6 syntax sugar apparently:
// http://stackoverflow.com/questions/22528967/es6-class-variable-alternatives
C.c = 1
C.c === 1
// Because `D.__proto__ === C`.
D.c === 1
// Nothing makes this work.
d.c === undefined

사전 정의 된 모든 객체가없는 단순화 된 다이어그램 :

(c)----->(1)
 |   i
 |
 |
 |[[Prototype]]
 |
 |
 v    __proto__
(C)<--------------(D)         (d)
| |                |           |
| |                |           |
| |prototype       |prototype  |[[Prototype]] 
| |                |           |
| |                |           |
| |                | +---------+
| |                | |
| |                | |
| |                v v
|[[Prototype]]    (D.prototype)--------> (inc2 function object)
| |                |             inc2
| |                |
| |                |[[Prototype]]
| |                |
| |                |
| | +--------------+
| | |
| | |
| v v
| (C.prototype)------->(inc function object)
|                inc
v
Function.prototype

다음이 어떻게 작동하는지 연구 해 봅시다.

c = new C(1)
c.inc() === 2

첫번째 라인 세트 c.i1 "4)"에 설명 된대로 .

두 번째 줄에서, 우리가 할 때 :

c.inc()
  • .inc[[Prototype]]체인을 통해 발견됩니다 : c-> C-> C.prototype->inc
  • Javascript로 함수를 호출하면 X.Y()JavaScript 가 함수 호출 내에서 자동으로 this동일하게 설정 됩니다 !XY()

똑같은 논리도 설명 d.inc하고d.inc2 있습니다.

이 기사 https://javascript.info/class#not-just-a-syntax-sugarclass알 가치가있는 추가 효과를 언급합니다 . 일부 class키워드 는 키워드 가 없으면 달성 할 수 없습니다 (TODO check which).


1
@tomasb 감사합니다! "어디에이 기능이 있는지 모르겠습니다": 몇 가지 동적 언어를 본 후 클래스 시스템에서 가장 중요한 것은 .조회 작동 방식 (및 데이터 사본 수)입니다. . 그래서 나는 그 점을 이해하기 시작했습니다. 나머지는 Google + 블로그 게시물 + Js 통역사입니다. :)
Ciro Santilli 冠状 病毒 审查 六四 事件 法轮功

1
"4) f = new F를 수행 할 때 new도 f.constructor = F"를 설정했기 때문에 g.constructor === Object 인 이유를 알 수 없습니다. 더 설명해 주시겠습니까? 어쨌든 이것은 내가 찾고있는 가장 좋은 대답입니다. 정말 고맙습니다!
nguyenngoc101

@ nguyenngoc101 감사합니다! sets f.constructor = F부분 노골적 잘못 또한 부와 모순이었다 .constructor통해 발견 .프로토 체인 참조. 지금 고쳤습니다.
Ciro Santilli 冠状 病毒 审查 六四 事件 法轮功

생성자 함수를 생성하고 새로운 연산자를 사용하여 인스턴스를 만들려고하면 모든 토론에서 내가 얻는 것 (클래식 상속에서 온 것) 프로토 객체에 첨부 된 메소드와 속성 만 가져 오므로 모든 메소드를 첨부해야합니다. 상속을 원한다면 객체를 프로토 타이핑하는 속성이 있습니다.
blackHawk

1
@CiroSantilli 刘晓波 死 六四 事件 法轮功 Chromium의 버그라고 생각하지 않습니다. f프로토 타입이 F시공 시점에서만 설정되는 증상 일 뿐이라고 생각합니다 . 처음 구축 된 후 언제든지 f알거나 신경 쓰지 않습니다 F.prototype.
John Glassmyer

76

prototype수업을 할 수 있습니다. 사용하지 않으면 prototype정적이됩니다.

다음은 간단한 예입니다.

var obj = new Object();
obj.test = function() { alert('Hello?'); };

위의 경우 정적 기능 호출 테스트가 있습니다. 이 함수는 obj가 클래스라고 상상할 수있는 obj.test에서만 액세스 할 수 있습니다.

아래 코드에서와 같이

function obj()
{
}

obj.prototype.test = function() { alert('Hello?'); };
var obj2 = new obj();
obj2.test();

obj는 이제 인스턴스화 할 수있는 클래스가되었습니다. obj의 여러 인스턴스가 존재할 수 있으며 모두test 기능이 있습니다.

위의 내 이해입니다. 나는 그것을 커뮤니티 위키로 만들고 있으므로, 내가 틀렸다면 사람들이 나를 바로 잡을 수 있습니다.


13
-1 : prototype인스턴스가 아닌 생성자 함수의 속성입니다. 즉 코드가 잘못되었습니다! 아마도 당신 __proto__은 객체의 비표준 속성을 의미 했지만 그것은 완전히 다른 짐승입니다.
Christoph

@Christoph-지적 해 주셔서 감사합니다. 샘플 코드를 업데이트했습니다.
Ramesh 2012

3
더 많은 것이 있습니다 ... 게다가 JavaScript는 클래스 기반 언어가 아닙니다. 프로토 타입을 통한 상속을 다루기 때문에 차이점을 더 자세히 다루어야합니다!
제임스

5
나는이 대답이 약간 오해라고 생각합니다.
Armin Cifuentes

어쩌면 그 대답은 '미스 가이 딩'일 수도 있지만 프로토 타입이 어떤 용도로 사용되는지 설명하면 수백 번의 '업'표를 얻은 '답변'이 모두 끝난 후 나에게 분명합니다. 감사합니다.
Aleks

66

이 글을 읽은 후 JavaScript Prototype Chain과 혼동 된 느낌이 들었습니다.

http://iwiki.readthedocs.org/en/latest/javascript/js_core.html#inheritance 함수 객체의 * [[protytype]] * 및 <code> prototype </ code> 속성

프로토 타입 체인 별 JavaScript 상속을 표시하는 명확한 차트입니다

http://www.javascriptbank.com/javascript/article/JavaScript_Classical_Inheritance/

이 예제에는 코드와 멋진 다이어그램이 포함 된 예제가 포함되어 있습니다.

프로토 타입 체인은 궁극적으로 Object.prototype으로 대체됩니다.

서브 클래스의 프로토 타입을 상위 클래스의 오브젝트와 동일하게 설정하여 매번 프로토 타입 체인을 기술적으로 확장 할 수 있습니다.

JavaScript 프로토 타입 체인을 이해하는 데 도움이되기를 바랍니다.


Javascript에서 다중 상속이 가능합니까?

Foo는 여기에 객체 리터럴입니까 아니면 함수 객체입니까? 객체 리터럴 인 경우 Foo.prototype이 생성자를 통해 Foo를 다시 가리 키지 않을 것이라고 생각합니다.
Madhur Ahuja

@ user3376708 자바 스크립트는 단일 상속만을 지원합니다 ( 소스 )
라파엘 Eyng

@ Nuno_147 처음에는 명확하지 않지만, 충분히 오래 보면 무언가를 얻을 수 있습니다.
marcelocra

3
무슨 [[Prototype]]의미 인지 설명해 주실 수 있습니까 ?
CodyBugstein

40

모든 객체에는 [[Prototype]] 내부 속성이 있으며 이를 다른 객체에 연결합니다.

object [[Prototype]]  anotherObject

전통적인 자바 스크립트에서 링크 된 객체는 prototype함수 의 속성입니다 :

object [[Prototype]]  aFunction.prototype

일부 환경은 [[프로토 타입]]__proto__다음 과 같이 노출합니다 .

anObject.__proto__ === anotherObject

당신은 만들 [[프로토 타입]] 객체를 생성 링크를.

// (1) Object.create:
var object = Object.create(anotherObject)
// object.__proto__ = anotherObject

// (2) ES6 object initializer:
var object = { __proto__: anotherObject };
// object.__proto__ = anotherObject

// (3) Traditional JavaScript:
var object = new aFunction;
// object.__proto__ = aFunction.prototype

따라서 이러한 진술은 동일합니다.

var object = Object.create(Object.prototype);
var object = { __proto__: Object.prototype }; // ES6 only
var object = new Object;

실제로 문장 Object.prototype에서 링크 대상 ( )을 볼 수 없습니다 . 대신 대상은 생성자에 의해 암시됩니다 (Object )에 .

생각해 내다:

  • 모든 객체에는 링크 [[Prototype]]이 있으며 때로는 __proto__로 노출됩니다 .
  • 모든 기능에는 prototype 속성이 있으며 처음에는 빈 객체를 보유합니다.
  • new 로 생성 된 객체 는prototype 는 생성자 속성에 .
  • 함수가 생성자로 사용되지 않으면 prototype 로 사용되지 않으면 속성이 사용되지 않습니다.
  • 생성자가 필요하지 않으면 대신 Object.create 를 사용 하십시오new .

1
개정 5는 Object.create ()에 대한 정보를 포함하여 유용한 정보를 제거했습니다. 개정 4를 참조하십시오 .
Palec

@Palec 무엇을 다시 추가해야하나요?
sam

2
IMO는 적어도 Object.create()문서 링크 , @sam에 대한 링크 입니다. 링크가 __proto__되고 Object.prototype개선 될 것입니다. 그리고 프로토 타입이 생성자와 작동하는 방식에 대한 예제를 좋아 Object.create()했지만 아마도 길고 덜 관련된 부분 일 것입니다.
Palec

생성자 함수를 생성하고 새로운 연산자를 사용하여 인스턴스를 만들려고하면 모든 토론에서 내가 얻는 것 (클래식 상속에서 온 것) 프로토 객체에 첨부 된 메소드와 속성 만 가져 오므로 모든 메소드를 첨부해야합니다. 상속을 원한다면 객체를 프로토 타이핑하는 속성이 있습니다.
blackHawk

29

자바 스크립트는 일반적인 의미에서 상속을받지 않지만 프로토 타입 체인을 가지고 있습니다.

프로토 타입 체인

객체에서 객체의 멤버를 찾을 수 없으면 프로토 타입 체인에서 객체를 찾습니다. 체인은 다른 객체로 구성됩니다. 주어진 인스턴스의 프로토 타입은__proto__ 변수를 . 자바 스크립트의 클래스와 인스턴스 사이에는 차이가 없으므로 모든 객체에는 하나가 있습니다.

프로토 타입에 함수 / 변수를 추가하면 모든 인스턴스가 아니라 메모리에 한 번만 있어야한다는 장점이 있습니다.

프로토 타입 체인은 다른 많은 객체로 구성 될 수 있으므로 상속에도 유용합니다.


1
FF와 Chrome은 proto를 지원 하지만 IE 나 Opera 는 지원 하지 않습니다.

Georg, 멍청한 놈을 분명히하십시오- "자바 스크립트의 클래스와 인스턴스에는 차이가 없습니다." -좀 더 자세히 설명해 주시겠습니까? 어떻게 작동합니까?
Hamish Grubijan

생성자 함수를 생성하고 새로운 연산자를 사용하여 인스턴스를 만들려고하면 모든 토론에서 내가 얻는 것 (클래식 상속에서 온 것) 프로토 객체에 첨부 된 메소드와 속성 만 가져 오므로 모든 메소드를 첨부해야합니다. 상속을 원한다면 객체를 프로토 타이핑하는 속성이 있습니다.
blackHawk

28

이 기사는 길다. 그러나 JavaScript Inheritance의 "prototypical"특성에 관한 대부분의 쿼리가 명확해질 것입니다. 그리고 훨씬 더. 전체 기사를 읽으십시오.

JavaScript는 기본적으로 두 가지 종류의 데이터 유형이 있습니다

  • 비 객체
  • 사물

비 객체

다음은 비 객체 데이터 유형입니다

  • 숫자 (NaN 및 무한대 포함)
  • 부울 값 (true, false)
  • 찾으시는 주소가 없습니다

이러한 데이터 유형은 typeof 연산자 를 사용할 때 다음을 반환합니다.

typeof "string literal" (또는 문자열 리터럴을 포함하는 변수) === 'string'

typeof 5 (또는 숫자 리터럴 또는 숫자 리터럴 또는 NaN 또는 Infynity를 포함하는 변수 ) === 'number'

typeof true (또는 false 또는 true 또는 false를 포함하는 변수 ) === 'boolean'

정의되지 않은 typeof (또는 정의되지 않은 변수 또는 undefined를 포함하는 변수 ) === 'undefined'

문자열 , 숫자부울 데이터 형식으로 모두 표현 될 수 객체비는 객체 들이 그들의 대해서 typeof 항상 === '객체'는 객체로 표시됩니다 .When을. 객체 데이터 형식을 이해하면 다시 돌아옵니다.

사물

객체 데이터 유형은 두 가지 유형으로 더 나눌 수 있습니다

  1. 함수 타입 객체
  2. 비 함수형 객체

기능 유형의 객체는 문자열을 반환 그들이다 '기능을'대해서 typeof 연산자를 사용합니다. new 연산자를 사용하여 새 객체를 만들 수있는 모든 사용자 정의 함수와 모든 내장 JavaScript 객체가이 범주에 속합니다. 예를 들어.

  • 목적
  • 번호
  • 부울
  • 정렬
  • 타입 배열
  • 정규식
  • 함수
  • new 연산자를 사용하여 새 개체를 만들 수있는 다른 모든 내장 개체
  • UserDefinedFunction 함수 () {/ * 사용자 정의 코드 * /}

따라서 typeof (Object) === typeof (String) === typeof (Number) === typeof (Boolean) === typeof (Array) === typeof (RegExp) === typeof (Function) == = typeof (UserDefinedFunction) === '함수'

모든 함수 유형 객체 는 실제로 내장 JavaScript 객체 Function 의 인스턴스입니다 ( 함수 객체 포함, 즉 재귀 적으로 정의 됨). 마치이 객체들이 다음과 같이 정의 된 것처럼

var Object= new Function ([native code for object Object])
var String= new Function ([native code for object String])
var Number= new Function ([native code for object Number])
var Boolean= new Function ([native code for object Boolean])
var Array= new Function ([native code for object Array])
var RegExp= new Function ([native code for object RegExp])
var Function= new Function ([native code  for object Function])
var UserDefinedFunction= new Function ("user defined code")

언급했듯이 함수 유형 객체new 연산자를 사용하여 새 객체를 더 만들 수 있습니다 . 예를 들어 Object , String , Number , Boolean , Array , RegExp 또는 UserDefinedFunction 유형의 객체 는 다음을 사용하여 만들 수 있습니다.

var a=new Object() or var a=Object() or var a={} //Create object of type Object
var a=new String() //Create object of type String
var a=new Number() //Create object of type Number
var a=new Boolean() //Create object of type Boolean
var a=new Array() or var a=Array() or var a=[]  //Create object of type Array
var a=new RegExp() or var a=RegExp() //Create object of type RegExp
var a=new UserDefinedFunction() 

이렇게 생성 된 객체는 모두 Non Function 유형의 객체 이며 typeof === 'object'를 반환합니다 . 이러한 모든 경우에 객체 "a"는 new 연산자를 사용하여 객체를 더 이상 만들 수 없습니다. 따라서 다음은 잘못되었습니다

var b=new a() //error. a is not typeof==='function'

내장 객체 Mathtypeof === 'object' 입니다. 따라서 Math 유형의 새 객체는 new 연산자로 만들 수 없습니다.

var b=new Math() //error. Math is not typeof==='function'

또한 Object , ArrayRegExp 함수는 new 연산자를 사용하지 않고도 새 객체를 만들 수 있습니다 . 그러나 다음과 같은 사람들은 그렇지 않습니다.

var a=String() // Create a new Non Object string. returns a typeof==='string' 
var a=Number() // Create a new Non Object Number. returns a typeof==='number'
var a=Boolean() //Create a new Non Object Boolean. returns a typeof==='boolean'

사용자 정의 함수는 특별한 경우입니다.

var a=UserDefinedFunction() //may or may not create an object of type UserDefinedFunction() based on how it is defined.

함수 유형 객체 는 새로운 객체를 생성 할 수 있기 때문에 생성자 라고도 합니다.

정의 된 모든 생성자 / 함수 (내장 또는 사용자 정의에 관계없이)에는 기본적으로 값이 "프로토 타입" 이라는 속성이 자동으로 설정됩니다. 이 객체 자체에는 기본적으로 생성자 / 함수를 다시 참조하는 "생성자" 라는 속성이 있습니다. 있습니다.

예를 들어 함수를 정의 할 때

function UserDefinedFunction()
{
}

다음은 자동으로 발생합니다

UserDefinedFunction.prototype={constructor:UserDefinedFunction}

"prototype"속성Function 유형 객체 에만 존재 하며 비 Function 유형 객체 에는 존재 하지 않습니다 .

이는 새로운 객체를 사용하여 새 객체를 만들 때 생성자 함수의 현재 프로토 타입 객체에서 모든 속성과 메서드를 상속하기 때문입니다. 즉, 생성자 함수의 현재 프로토 타입 객체가 참조하는 객체를 참조하는 새로 만든 객체에 내부 참조 가 만들어 지기 때문 입니다.

상속 된 속성을 참조하기 위해 개체에 생성 된 이 "내부 참조"개체의 프로토 타입 (생성자의 "prototype" 속성이 참조하지만 다른 것과는 다른 개체 )으로 알려져 있습니다. 모든 객체 (함수 또는 비 함수)의 경우 Object.getPrototypeOf () 메소드를 사용하여 검색 할 수 있습니다 . 이 방법을 사용하면 객체의 프로토 타입 체인을 추적 할 수 있습니다.

또한 생성 된 모든 객체 ( Function type 또는 Non Function type )에는 Constructor 함수의 prototype 속성이 참조하는 객체에서 상속 된 "constructor" 속성이 있습니다. 기본적으로이 "생성자" 속성은 생성자 생성자 를 생성 한 생성자 함수 를 참조합니다 ( 생성자 함수의 기본 "프로토 타입"이 변경되지 않은 경우).

모든 함수 유형 객체 에서 생성자 함수는 항상 함수 Function () {}입니다.

들어 비 기능 형 객체 (Math 객체 내장 예를 들어 자바 스크립트) 생성자 함수를 생성하는 기능입니다. 를 들어 수학 객체 그것이 기능 개체 () {} .

위에서 설명한 모든 개념은 지원 코드없이 이해하기가 다소 어려울 수 있습니다. 개념을 이해하려면 다음 코드를 한 줄씩 살펴보십시오. 더 잘 이해하기 위해 실행하십시오.

function UserDefinedFunction()
{ 

} 

/* creating the above function automatically does the following as mentioned earlier

UserDefinedFunction.prototype={constructor:UserDefinedFunction}

*/


var newObj_1=new UserDefinedFunction()

alert(Object.getPrototypeOf(newObj_1)===UserDefinedFunction.prototype)  //Displays true

alert(newObj_1.constructor) //Displays function UserDefinedFunction

//Create a new property in UserDefinedFunction.prototype object

UserDefinedFunction.prototype.TestProperty="test"

alert(newObj_1.TestProperty) //Displays "test"

alert(Object.getPrototypeOf(newObj_1).TestProperty)// Displays "test"

//Create a new Object

var objA = {
        property1 : "Property1",
        constructor:Array

}


//assign a new object to UserDefinedFunction.prototype
UserDefinedFunction.prototype=objA

alert(Object.getPrototypeOf(newObj_1)===UserDefinedFunction.prototype)  //Displays false. The object referenced by UserDefinedFunction.prototype has changed

//The internal reference does not change
alert(newObj_1.constructor) // This shall still Display function UserDefinedFunction

alert(newObj_1.TestProperty) //This shall still Display "test" 

alert(Object.getPrototypeOf(newObj_1).TestProperty) //This shall still Display "test"


//Create another object of type UserDefinedFunction
var newObj_2= new UserDefinedFunction();

alert(Object.getPrototypeOf(newObj_2)===objA) //Displays true.

alert(newObj_2.constructor) //Displays function Array()

alert(newObj_2.property1) //Displays "Property1"

alert(Object.getPrototypeOf(newObj_2).property1) //Displays "Property1"

//Create a new property in objA
objA.property2="property2"

alert(objA.property2) //Displays "Property2"

alert(UserDefinedFunction.prototype.property2) //Displays "Property2"

alert(newObj_2.property2) // Displays Property2

alert(Object.getPrototypeOf(newObj_2).property2) //Displays  "Property2"

모든 객체의 프로토 타입 체인은 궁극적으로 Object.prototype (자체에 프로토 타입 객체가 없음)으로 거슬러 올라갑니다. 다음 코드를 사용하여 객체의 프로토 타입 체인을 추적 할 수 있습니다

var o=Starting object;

do {
    alert(o + "\n" + Object.getOwnPropertyNames(o))

}while(o=Object.getPrototypeOf(o))

다양한 객체의 프로토 타입 체인은 다음과 같이 작동합니다.

  • 모든 Function 객체 (내장 Function 객체 포함)-> Function.prototype-> Object.prototype-> null
  • 간단한 객체 (내장 Math 객체를 포함하여 new Object () 또는 {}에 의해 생성됨)-> Object.prototype-> null
  • new 또는 Object.create-> 하나 이상의 프로토 타입 체인으로 생성 된 오브젝트-> Object.prototype-> null

프로토 타입없이 객체를 만들려면 다음을 사용하십시오.

var o=Object.create(null)
alert(Object.getPrototypeOf(o)) //Displays null

Constructor의 prototype 속성을 null로 설정하면 null 프로토 타입을 가진 객체가 생성 될 것이라고 생각할 수 있습니다. 그러나 이러한 경우 새로 만든 객체의 프로토 타입은 Object.prototype으로 설정되고 생성자는 Object 함수로 설정됩니다. 이것은 다음 코드로 설명됩니다

function UserDefinedFunction(){}
UserDefinedFunction.prototype=null// Can be set to any non object value (number,string,undefined etc.)

var o=new UserDefinedFunction()
alert(Object.getPrototypeOf(o)==Object.prototype)   //Displays true
alert(o.constructor)    //Displays Function Object

이 기사의 요약에서 다음

  • 두 가지 유형의 객체가 있습니다 기능 유형비 기능 유형
  • Function 유형 객체 만 new 연산자를 사용하여 새 객체를 만들 수 있습니다 . 이렇게 생성 된 객체는 비 기능 유형 객체입니다. 비 함수 타입 오브젝트는 상기 사용 목적 만들 수없는 새로운 오퍼레이터 .

  • 기본적으로 모든 함수 유형 개체 에는 "prototype" 속성이 있습니다. 이 "prototype" 속성 은 기본적으로 Function 형식 개체 자체를 참조 하는 "constructor" 속성 이있는 개체를 참조합니다 .

  • 모든 객체 ( 함수 유형비 함수 유형 )에는 기본적으로 생성 한 함수 유형 객체 / 생성자 를 참조하는 "생성자"속성이 있습니다.

  • 내부적으로 생성 된 모든 객체 는 생성자의 "prototype" 속성이 참조하는 객체를 참조 합니다. 이 객체는 생성 된 객체의 프로토 타입 으로 알려져 있습니다 (이것은 참조하는 함수 유형 객체 "prototype"속성과 다릅니다). 이 방법으로 생성 된 객체는 생성자의 "prototype"속성에 의해 참조 된 객체에 정의 된 메소드와 속성에 직접 액세스 할 수 있습니다 (객체 생성시).

  • 객체의 프로토 타입 (따라서 상속 된 속성 이름)을 사용하여 검색 할 수 있습니다 Object.getPrototypeOf () 메소드를. 실제로이 방법은 객체의 전체 프로토 타입 체인을 탐색하는 데 사용할 수 있습니다.

  • 모든 객체의 프로토 타입 체인은 궁극적으로 Object.prototype으로 추적합니다 (오브젝트가 Object.create (null)을 사용하여 생성되지 않은 경우 객체에 프로토 타입이없는 경우).

  • typeof (new Array ()) === 'object' 는 언어 설계에 의한 것이며 Douglas Crockford가 지적한 실수가 아닙니다.

  • 생성자의 프로토 타입 속성을 null (또는 undefined, number, true, false, string)로 설정하면 null 프로토 타입이있는 객체를 만들 수 없습니다. 이러한 경우 새로 생성 된 객체의 프로토 타입은 Object.prototype으로 설정되고 생성자는 Object 함수로 설정됩니다.

도움이 되었기를 바랍니다.


24

prototypal상속 개념은 많은 개발자에게 가장 복잡한 개념 중 하나입니다. prototypal inheritance더 잘 이해하기 위해 문제의 근원을 이해하려고 노력합시다 . plain함수 부터 시작하겠습니다 .

여기에 이미지 설명을 입력하십시오

에서 new연산자를 사용하면 Tree function이를 constructor함수 로 호출합니다 .

여기에 이미지 설명을 입력하십시오

모든 JavaScript기능 에는가 있습니다 prototype. 당신이 로그인하면 Tree.prototype, 당신은 얻을 ...

여기에 이미지 설명을 입력하십시오

위의 console.log()출력 을 보면 생성자 속성 Tree.prototype__proto__속성도 볼 수 있습니다. 을 __proto__나타내는 prototype이이 것을 function기반으로,이 그냥 보통이기 때문입니다 JavaScript function결코로 inheritance아직 설정, 그것은을 의미 Object prototype하는 단지 자바 스크립트에 내장 뭔가 ...

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype

이것은 .toString, .toValue, .hasOwnProperty등등 과 같은 것들을 가지고 있습니다 ...

__proto__가져온 내 mozilla는 더 이상 사용되지 않으며 Object.getPrototypeOf를 얻는 방법으로 대체되었습니다 object's prototype.

여기에 이미지 설명을 입력하십시오

Object.getPrototypeOf(Tree.prototype); // Object {} 

에 메소드를 추가합시다 Tree prototype.

여기에 이미지 설명을 입력하십시오

우리는 수정하고 지점을 Root추가 function했습니다.

여기에 이미지 설명을 입력하십시오

즉, instance의 를 만들면 메소드를 Tree호출 할 수 있습니다 branch.

여기에 이미지 설명을 입력하십시오

primitives또는 objects에 추가 할 수도 있습니다 Prototype.

여기에 이미지 설명을 입력하십시오

의은을 추가 할 수 있도록 child-tree우리에게 Tree.

여기에 이미지 설명을 입력하십시오

여기 에서 Tree로부터 Child상속받습니다. 여기서 prototype우리가하고있는 일은 Object.create()전달하는 것을 기반으로 새 객체를 만드는 방법을 사용하는 것입니다 Tree.prototype. 여기 있습니다 . 이 경우 우리가하는 일은 Child의 Tree프로토 타입을 프로토 타입 과 동일한 새 객체로 설정하는 것 입니다. 다음에을 지정 Child's constructor to Child하지 않으면을 설정합니다 Tree().

여기에 이미지 설명을 입력하십시오

Child지금 자신이 prototype__proto__포인트 TreeTree's prototype베이스에 포인트를 Object.

Child  
|
 \
  \
   Tree.prototype
   - branch
   |
   |
    \
     \
      Object.prototype
      -toString
      -valueOf
      -etc., etc.

이제 에서 원래 제공되는 instanceChild및 통화 를 만듭니다 . 에 대한 실제 정의는 없습니다 . 그러나 Child가 상속받은 곳.branchTreebranchChild prototypeRoot prototype

여기에 이미지 설명을 입력하십시오

JS에서는 모든 것이 객체가 아니며 모든 것이 객체처럼 작동 할 수 있습니다.

Javascriptstrings, number, booleans, undefined, null.그들은 같은 프리미티브를 가지고 object(i.e reference types)있지만 확실히처럼 행동 할 수 있습니다 object. 여기에 예를 보자.

여기에 이미지 설명을 입력하십시오

이 리스팅의 첫 번째 라인에서 primitive문자열 값이 name에 지정됩니다. 두 번째 줄은 이름과 같이 취급 object하고 charAt(0)점 표기법을 사용하여 호출합니다 .

이것은 뒤에서 일어나는 일입니다 : // JavaScript엔진이하는 일

여기에 이미지 설명을 입력하십시오

String object파괴되기 전에 하나의 명령문에 대해서만 존재합니다 (프로세스라고 함 autoboxing). 다시 우리로 돌아 갑시다 prototypal inheritance.

  • Javascriptdelegation기반을 통한 상속을 지원합니다 prototypes.
  • 각각 다른 속성 Function을 나타내는 prototype속성이 있습니다.
  • properties/functions로부터보고되는 object자체 또는를 통해 prototype존재하지가 않는 경우 체인

prototypeJS의 A yields는 다른 부모의 부모에게 있는 객체입니다 object. [즉, 위임] Delegation 은 무언가를 할 수없는 경우 다른 사람에게 대신해달라고 지시한다는 의미입니다.

여기에 이미지 설명을 입력하십시오

https://jsfiddle.net/say0tzpL/1/

위의 바이올린을 조회하면 개는 toString메소드에 액세스 할 수 있지만 그 메소드 는 사용할 수 없지만 프로토 타입 체인을 통해 사용할 수 있습니다.Object.prototype

여기에 이미지 설명을 입력하십시오

아래 중 하나를 보면 call모든에서 사용할 수 있는 방법 에 액세스하려고합니다 function.

여기에 이미지 설명을 입력하십시오

https://jsfiddle.net/rknffckc/

위의 바이올린을 조회하면 Profile함수에 call메소드에 액세스 할 수 있지만 메소드에는 사용할 수 없지만 프로토 타입 체인을 통해 사용할 수 있습니다.Function.prototype

여기에 이미지 설명을 입력하십시오

참고 : prototype 함수 생성자 __proto__의 속성 인 반면 함수 생성자에서 생성 된 객체의 속성입니다. 모든 함수에는 prototype값이 비어 있는 속성이 object있습니다. 함수의 인스턴스를 만들면 내부 속성을 얻 [[Prototype]]거나 __proto__참조가 Function의 프로토 타입입니다 constructor.

여기에 이미지 설명을 입력하십시오

위의 다이어그램은 약간 복잡해 보이지만 prototype chaining작동 방식 에 대한 전체 그림을 보여줍니다 . 이것을 천천히 살펴 보자.

두 가지 예이다 b1b2그 생성자, Bar부모 푸이며 프로토 체인으로부터의 두 가지 방법이 있습니다 identifyspeak비아 BarFoo

여기에 이미지 설명을 입력하십시오

https://jsfiddle.net/kbp7jr7n/

위의 코드를 조회 Foo하면 메서드가있는 생성자 identify()와 메서드가있는 Bar생성자가 있습니다 speak. 우리는이 생성 Barb1b2그 부모 유형입니다 Foo. 의 speak메소드 를 호출 하는 동안 체인을 Bar통해 스포크를 호출하는 사람을 식별 할 수 prototype있습니다.

여기에 이미지 설명을 입력하십시오

Bar이제 모든 메소드 Foo가에 정의되어 있습니다 prototype. 의는 이해를 더 살펴 보겠습니다 Object.prototype그리고 Function.prototype그들이 어떻게 관련되는지를. 당신의 생성자를 보면 Foo, Bar하고 Object있습니다 Function constructor.

여기에 이미지 설명을 입력하십시오

prototype의가 Bar있다 Foo, prototypeFooIS Object당신이 자세히 보면 경우 prototypeFoo관련이있다 Object.prototype.

여기에 이미지 설명을 입력하십시오

이를 닫기 전에 위의 모든 것을 요약 하기 위해 여기에 작은 코드 조각으로 싸서 보자 . 우리는 instanceof연산자 를 사용하여 체인에 체인의 특성 object이 있는지 확인 하고 아래 prototypeprototype속성은 constructor전체 큰 다이어그램을 요약합니다.

여기에 이미지 설명을 입력하십시오

나는이 추가가 약간의 정보가 있기를 바랍니다. 나는이 종류가 파악하기가 클 수 있다는 것을 알고 있습니다 ... 간단히 말하면 그것은 객체에 연결된 객체 일뿐입니다 !!!!


22

이 ".prototype"속성의 정확한 목적은 무엇입니까?

표준 클래스에 대한 인터페이스는 확장 가능해집니다. 예를 들어, Array클래스를 사용하고 있으며 모든 배열 객체에 대해 사용자 정의 직렬 변환기를 추가해야합니다. 프로토 타입 속성은 사용자가 클래스에 사용할 수있는 정확한 멤버 / 메소드 세트를 제어 할 수 있도록하여이 문제를 해결합니다.

프로토 타입을 추가 vtable 포인터로 생각하십시오. 원래 클래스에서 일부 멤버가 누락되면 런타임에 프로토 타입이 조회됩니다.


21

프로토 타입 체인을 두 가지 범주로 분류하면 도움이 될 수 있습니다.

생성자를 고려하십시오.

 function Person() {}

의 값은 Object.getPrototypeOf(Person)함수입니다. 실제로는 Function.prototype입니다. 이후 Person함수로서 생성하고, 그 모든 기능을 가지고 동일한 기능 프로토 타입 객체를 공유한다. 와 동일 Person.__proto__하지만 해당 속성을 사용해서는 안됩니다. 어쨌든 Object.getPrototypeOf(Person)프로토 타입 체인이라는 사다리를 효과적으로 걸을 수 있습니다.

위쪽 방향의 체인은 다음과 같습니다.

    PersonFunction.prototypeObject.prototype(종료점)

이 프로토 타입 체인은 생성Person 할 수 있는 객체와 관련이 거의 없습니다. . 생성 된 객체에는 자체 프로토 타입 체인이 있으며이 체인은 위에서 언급 한 것과 공통된 조상을 가질 수 없습니다.

이 객체를 예로 들어 보겠습니다.

var p = new Person();

pPerson 과 직접적인 프로토 타입 체인 관계가 없습니다 . 그들의 관계는 다릅니다. 객체 p 에는 자체 프로토 타입 체인이 있습니다. 를 사용하면 Object.getPrototypeOf다음과 같은 체인을 찾을 수 있습니다.

    pPerson.prototypeObject.prototype(종료점)

이 체인에는 함수 객체가 없습니다 (물론 가능할 수도 있음).

그래서 Person자신의 삶을 사는 두 종류의 사슬과 관련이있는 것 같습니다. 한 체인에서 다른 체인으로 "점프"하려면 다음을 사용하십시오.

  1. .prototype: 생성자의 체인에서 생성 된 객체의 체인으로 이동합니다. 따라서이 속성은 함수 new에서만 사용할 수있는 함수 객체에 대해서만 정의 됩니다.

  2. .constructor: 생성 된 객체의 체인에서 생성자의 체인으로 이동합니다.

다음은 열로 표시된 두 가지 프로토 타입 체인을 시각적으로 나타낸 것입니다.

여기에 이미지 설명을 입력하십시오

요약하면 다음과 같습니다.

prototype속성은 주제의 프로토 타입 체인 에 대한 정보가 아니라 주제에 의해 생성 된 객체에 대한 정보를 제공합니다 .

재산의 이름이 prototype혼란을 초래할 수 있다는 것은 놀라운 일이 아닙니다 . 이 속성의 이름이 지정 prototypeOfConstructedInstances되었거나 해당 줄을 따라 있으면 더 명확했을 것입니다.

두 프로토 타입 체인간에 앞뒤로 이동할 수 있습니다.

Person.prototype.constructor === Person

이 대칭은 다른 객체를 명시 적으로 prototype 속성에 (나중에 자세히 설명).

하나의 함수 생성, 두 개의 객체 얻기

Person.prototype함수 Person가 작성 되는 동시에 작성된 오브젝트입니다 . 그것은이 Person그 생성자가 실제로 아직 실행하지 않은 경우에도, 생성자로. 따라서 두 개의 객체가 동시에 생성됩니다.

  1. 기능 Person자체
  2. 함수가 생성자로 호출 될 때 프로토 타입으로 작동 할 객체

둘 다 객체이지만 역할이 다릅니다. 함수 객체 생성 , 다른 객체가 함수가 구성됩니다 어떤 객체의 프로토 타입을 나타낸다. 프로토 타입 객체는 프로토 타입 체인에서 생성 된 객체의 부모가됩니다.

함수도 객체이기 때문에 자체 프로토 타입 체인에 자체 부모가 있지만이 두 체인은 서로 다른 것입니다.

다음은이 문제를 파악하는 데 도움이되는 몇 가지 평등입니다 true.

function Person() {};

// This is prototype chain info for the constructor (the function object):
console.log(Object.getPrototypeOf(Person) === Function.prototype);
// Step further up in the same hierarchy:
console.log(Object.getPrototypeOf(Function.prototype) === Object.prototype);
console.log(Object.getPrototypeOf(Object.prototype) === null);
console.log(Person.__proto__ === Function.prototype);
// Here we swap lanes, and look at the constructor of the constructor
console.log(Person.constructor === Function);
console.log(Person instanceof Function);

// Person.prototype was created by Person (at the time of its creation)
// Here we swap lanes back and forth:
console.log(Person.prototype.constructor === Person);
// Although it is not an instance of it:
console.log(!(Person.prototype instanceof Person));
// Instances are objects created by the constructor:
var p = new Person();
// Similarly to what was shown for the constructor, here we have
// the same for the object created by the constructor:
console.log(Object.getPrototypeOf(p) === Person.prototype);
console.log(p.__proto__ === Person.prototype);
// Here we swap lanes, and look at the constructor
console.log(p.constructor === Person);
console.log(p instanceof Person);

프로토 타입 체인에 레벨 추가

생성자 함수를 만들 때 프로토 타입 객체가 만들어 지더라도 해당 객체를 무시하고 해당 생성자가 만든 이후 인스턴스의 프로토 타입으로 사용할 다른 객체를 할당 할 수 있습니다.

예를 들어 :

function Thief() { }
var p = new Person();
Thief.prototype = p; // this determines the prototype for any new Thief objects:
var t = new Thief();

이제 t 의 프로토 타입 체인 은 p 의 프로토 타입 체인 보다 한 단계 길다 :

    tpPerson.prototypeObject.prototype(종료점)

다른 프로토 타입 체인이 더 이상되지 않습니다 : ThiefPerson자신의 프로토 타입 체인에 같은 부모를 공유하는 형제 자매는 다음과 같습니다 :

    Person}
    Thief  } → Function.prototypeObject.prototype(끝점)

이전에 제시된 그래픽을 다음과 같이 확장 할 수 있습니다 (원본 Thief.prototype은 생략 됨).

여기에 이미지 설명을 입력하십시오

파란색 선은 프로토 타입 체인을 나타내고 다른 색 선은 다른 관계를 나타냅니다.

  • 객체와 그 생성자 사이
  • 생성자와 객체 생성에 사용될 프로토 타입 객체 간


16

"프로토 타입 체인"을 obj_n.prop_X참조 할 때 재귀 규칙으로 설명하는 것이 도움이된다는 것을 알았습니다 .

경우에 obj_n.prop_X존재하지 않는 확인 obj_n+1.prop_X어디에obj_n+1 = obj_n.[[prototype]]

prop_Xk 번째 프로토 타입 객체에서가 발견 되면

obj_1.prop_X = obj_1.[[prototype]].[[prototype]]..(k-times)..[[prototype]].prop_X

Javascript 객체의 관계에 대한 그래프는 해당 등록 정보에서 찾을 수 있습니다.

js 객체 그래프

http://jsobjects.org


14

생성자가 객체를 만들면 해당 객체는 속성 참조를 확인하기 위해 생성자의 "prototype"속성을 암시 적으로 참조합니다. 생성자의 "prototype"속성은 프로그램 표현식 constructor.prototype에서 참조 할 수 있으며, 객체의 프로토 타입에 추가 된 속성은 상속을 통해 프로토 타입을 공유하는 모든 객체가 공유합니다.


11

여기에는 설명이 필요한 두 가지 별개의 관련 엔터티가 있습니다.

  • .prototype기능 의 속성.
  • 모든 객체 의 [[Prototype]][1] 속성 [2] .

이것들은 두 가지입니다.

[[Prototype]]특성 :

이것은 모든 [2] 객체 에 존재하는 속성입니다 .

여기에 저장된 것은 객체 자체로서 [[Prototype]]다른 객체를 가리키는 자체 객체를 가진 또 다른 객체입니다. 그 다른 물건에는 [[Prototype]]그 자체가 있습니다. 이 이야기는 (와 같은 .toString) 모든 객체에서 액세스 할 수있는 메소드를 제공하는 프로토 타입 객체에 도달 할 때까지 계속 됩니다.

[[Prototype]]속성은 형성 무엇의 일부입니다 [[Prototype]]체인. 이 체인 [[Prototype]]오브젝트는, 예를 들면,시, 조사되는 것이다 [[Get]]또는 [[Set]]동작은 개체에 대해 수행된다 :

var obj = {}
obj.a         // [[Get]] consults prototype chain
obj.b = 20    // [[Set]] consults prototype chain

.prototype특성 :

이것은 함수에서만 발견되는 특성입니다. 매우 간단한 기능 사용하기 :

function Bar(){};

.prototype속성 에는b.[[Prototype]] 수행 할 때 할당 될 개체 가 있습니다 var b = new Bar. 이것을 쉽게 확인할 수 있습니다.

// Both assign Bar.prototype to b1/b2[[Prototype]]
var b = new Bar;
// Object.getPrototypeOf grabs the objects [[Prototype]]
console.log(Object.getPrototypeOf(b) === Bar.prototype) // true

가장 중요한 하나 .prototype의는 점이다 Object기능 . 이 프로토 타입에는 모든 [[Prototype]]체인에 포함 된 프로토 타입 객체가 있습니다. 여기에 새로운 객체에 사용 가능한 모든 방법이 정의됩니다.

// Get properties that are defined on this object
console.log(Object.getOwnPropertyDescriptors(Object.prototype))

이제는 .prototype객체이므로 [[Prototype]]속성이 있습니다. 당신은 어떤 지정하지 않을 경우 Function.prototype1, .prototype[[Prototype]](원형 적 객체에 포인트를Object.prototype ). 새 기능을 만들 때마다 자동으로 수행됩니다.

이런 식으로 new Bar;프로토 타입 체인을 설정할 때마다 모든 것이 정의되고 다음 Bar.prototype과 같이 정의됩니다 Object.prototype.

var b = new Bar;
// Get all Bar.prototype properties
console.log(b.__proto__ === Bar.prototype)
// Get all Object.prototype properties
console.log(b.__proto__.__proto__ === Object.prototype)

이 때 수 있도록 할당을 Function.prototype당신이하고있는 모든 다른 개체를 포함하는 프로토 타입 체인을 확장입니다. 단일 연결 목록의 삽입과 같습니다.

이것은 기본적으로 [[Prototype]]체인을 변경하여 지정된 객체에 정의 된 속성이 Function.prototype함수에 의해 생성 된 객체에 표시되도록합니다.


[1 : 아무도 혼동하지 않습니다. 많은 구현 에서 __proto__속성 을 통해 사용할 수 있습니다 .
[2] :를 제외한 모두 null.


10

프로토 타입에 대한 이해를 알려 드리겠습니다. 나는 상속을 다른 언어와 비교하지 않을 것입니다. 사람들이 언어 비교를 그만두고 언어 자체를 이해하기를 바랍니다. 프로토 타입과 프로토 타입 상속을 이해하는 것은 매우 간단합니다. 아래에서 설명하겠습니다.

프로토 타입은 제품을 만드는 데 기반을 둔 모델과 같습니다. 이해해야 할 중요한 점은 다른 객체를 프로토 타입으로 사용하여 객체를 만들 때 프로토 타입과 제품 간의 연결이 영구적이라는 것입니다. 예를 들어 :

var model = {x:2};
var product = Object.create(model);
model.y = 5;
product.y
=>5

모든 객체에는 Object.getPrototypeOf()함수 로 액세스 할 수있는 [[prototype]]이라는 내부 속성이 포함되어 있습니다 . Object.create(model)새 객체를 만들고 [[prototype]] 속성을 객체 모델로 설정 합니다. 따라서 그렇게 Object.getPrototypeOf(product)하면 객체 모델 을 얻게됩니다 .

제품의 속성 은 다음과 같은 방식으로 처리됩니다.

  • 속성 값을 읽기 위해 속성에 액세스하면 스코프 체인에서 검색됩니다. 변수 검색은 제품 에서 시작합니다 프로토 타입으로 . 이러한 변수가 검색에서 발견되면 검색이 바로 중지되고 값이 리턴됩니다. 이러한 변수를 범위 체인에서 찾을 수 없으면 undefined가 반환됩니다.
  • 속성이 기록 (변경)되면 속성은 항상 제품 개체 에 기록됩니다 . 는 IF 제품은 이미 그러한 속성이없는, 그것은 내재적으로 작성하고 작성된 것입니다.

프로토 타입 속성을 사용하여 이러한 객체를 연결하는 것을 프로토 타입 상속이라고합니다. 너무 간단합니다. 동의하십니까?


할당시 항상 제품에 쓰여지는 것은 아닙니다. 인스턴스 특정 멤버를 초기화해야하고 공유 멤버가 프로토 타입을 진행할 수 있다는 것을 명확하게 알 수는 없습니다. 특히 인스턴스 별 변경 가능한 멤버가있는 경우 : stackoverflow.com/questions/16063394/…
HMR

HMR : 귀하의 예에서, ben.food.push ( "Hamburger"); line은 다음과 같은 이유로 프로토 타입 객체의 속성을 변경합니다. 2.) 해당 ben.food 객체의 푸시 기능이 실행됩니다. 내 대답에 모드를 쓰면 다음과 같이 명시 적으로 값을 설정할 때를 의미합니다. ben.food = [ 'Idly']; 이렇게하면 항상 제품 객체에 새 속성이 생성되고 (없는 경우) 속성이 할당됩니다.
Aravind

HMR : 귀하의 의견에 감사 드리며, 제 이해력을 생각하고 테스트하게되었습니다.
Aravind

ben.food를 다시 지정할 때 Object.defineProperty, Object.defineProperties 또는 Object.create를 사용하여 두 번째 인수를 사용하여 음식을 만들지 않는 한 음식 구성원을 가리게됩니다 (항상 그런 것은 아님). getter setter를 만들 때 재 지정으로 프로토 타입을 변경할 수도 있습니다. 상속 패턴에 관해서는 생성자 함수가 이해하기 어렵고 몇 가지 중요한 문제가 있지만 이해하면 좋습니다. JavaScript의 상속은 프로토 타입 설정으로 시작하고 끝나지 않으며 초기화 (생성자)도 다시 사용해야합니다.
HMR

귀하의 답변은 프로토 타입을 설명하는 데 좋지만 JavaScript 및 인스턴스 특정 멤버의 상속을 지나치게 단순화하여 잘못 해석 될 수 있습니다. 인스턴스에서 프로토 타입 멤버를 변경하면 다른 인스턴스에 영향을주는 이유가 많이 있습니다.
HMR


10

다음 keyValueStore객체를 고려하십시오 .

var keyValueStore = (function() {
    var count = 0;
    var kvs = function() {
        count++;
        this.data = {};
        this.get = function(key) { return this.data[key]; };
        this.set = function(key, value) { this.data[key] = value; };
        this.delete = function(key) { delete this.data[key]; };
        this.getLength = function() {
            var l = 0;
            for (p in this.data) l++;
            return l;
        }
    };

    return  { // Singleton public properties
        'create' : function() { return new kvs(); },
        'count' : function() { return count; }
    };
})();

이 작업을 수행하여이 객체의 새 인스턴스를 만들 수 있습니다.

kvs = keyValueStore.create();

이 객체의 각 인스턴스에는 다음과 같은 공용 속성이 있습니다.

  • data
  • get
  • set
  • delete
  • getLength

이제이 keyValueStore객체의 인스턴스를 100 개 생성한다고 가정하겠습니다 . 비록 get, set, delete, getLength이 100 개 인스턴스 각각에 대해 동일한 일을 할 것, 모든 인스턴스는이 기능의 복사본을 가지고있다.

이제 하나 getset, deletegetLengthcopy 만 가질 수 있고 각 인스턴스가 동일한 기능을 참조 한다고 상상해보십시오 . 이것은 성능을 높이고 메모리를 덜 필요로합니다.

그것이 프로토 타입이 들어온 곳입니다. 프로토 타입은 상속되지만 인스턴스에 의해 복사되지 않는 속성의 "청사진"입니다. 따라서 이것은 객체의 모든 인스턴스에 대해 메모리에 한 번만 존재하며 모든 해당 인스턴스가 공유 함을 의미합니다.

이제, 그 keyValueStore물체를 다시 고려 하십시오. 나는 이것을 다음과 같이 다시 작성할 수 있습니다 :

var keyValueStore = (function() {
    var count = 0;
    var kvs = function() {
        count++;
        this.data = {};
    };

    kvs.prototype = {
        'get' : function(key) { return this.data[key]; },
        'set' : function(key, value) { this.data[key] = value; },
        'delete' : function(key) { delete this.data[key]; },
        'getLength' : function() {
            var l = 0;
            for (p in this.data) l++;
            return l;
        }
    };

    return  {
        'create' : function() { return new kvs(); },
        'count' : function() { return count; }
    };
})();

이는 keyValueStore모든 메소드가 이제 프로토 타입에 배치된다는 점을 제외 하면 이전 버전의 오브젝트 와 정확히 동일합니다 . 이것이 의미하는 바는 100 개의 인스턴스 모두가 각각 고유 한 복사본을 가지지 않고이 네 가지 방법을 공유한다는 것입니다.


9

요약:

  • 함수는 자바 스크립트의 객체이므로 속성을 가질 수 있습니다
  • (생성자) 함수에는 항상 프로토 타입 속성이 있습니다
  • new키워드 와 함께 생성자로 함수를 사용 하면 객체가 프로토 타입을 가져옵니다. 이 프로토 타입에 대한 참조 __proto__는 새로 작성된 오브젝트 의 특성에서 찾을 수 있습니다 .
  • __proto__속성은 prototype생성자 함수 의 속성을 나타냅니다 .

예:

function Person (name) {
  this.name = name;
}

let me = new Person('willem');

console.log(Person.prototype) // Person has a prototype property

console.log(Person.prototype === me.__proto__) // the __proto__ property of the instance refers to prototype property of the function.

이것이 유용한 이유는 무엇입니까?

Javascript에는 'prototypal inheritance' 라는 객체의 속성을 찾을 때 메커니즘 이 있습니다. 기본적으로 수행되는 작업은 다음과 같습니다.

  • 속성이 개체 자체에 있는지 먼저 확인합니다. 그렇다면이 속성이 반환됩니다.
  • 속성이 객체 자체에 없으면 '프로토 체인을 등반'합니다. 기본적으로 proto 속성이 참조하는 개체를 봅니다 . 거기에서 proto가 참조하는 객체에서 속성을 사용할 수 있는지 확인합니다.
  • 이 속성이 프로토 객체 에 없으면 프로토 체인을 Object 객체까지 올립니다.
  • 객체와 프로토 타입 체인에서 속성을 찾을 수 없으면 정의되지 않은 상태로 반환됩니다.

예를 들면 다음과 같습니다.

function Person(name) {
  this.name = name;
}

let mySelf = new Person('Willem');

console.log(mySelf.__proto__ === Person.prototype);

console.log(mySelf.__proto__.__proto__ === Object.prototype);

최신 정보:

__proto__프로토 타입 객체 참조를 얻는 더 좋은 방법은 대부분의 최신 브라우저에서 구현되지만 이 속성은 더 이상 사용되지 않습니다.

Object.getPrototypeOf()


7

나는 이런 종류의 것들을 이해할 때 항상 유추를 좋아합니다. 프로토 타입이 훨씬 더 단순한 패러다임 임에도 불구하고 '프로토 타입 상속'은 클래스베이스 상속과 비교하면 상당히 혼란 스럽다. 실제로 프로토 타입에는 상속이 없으므로 이름 자체가 오해의 소지가 있으므로 '위임'유형에 가깝습니다.

이것을 상상해보십시오 ....

당신은 고등학교에 다니고 있으며 수업 중에 있고 오늘 예정된 퀴즈를 가지고 있지만 답변을 채울 수있는 펜은 없습니다. 도!

펜을 가지고 있을지도 모르는 친구 피니 우스 옆에 앉아 있습니다. 당신은 묻습니다. 그리고 그는 책상 주위를 보지 못했지만 "펜이 없습니다"라고 말하는 대신 다른 친구 인 Derp와 함께 펜이 있는지 확인하는 좋은 친구입니다. Derp는 실제로 여분의 펜을 가지고 있으며 Finnius로 다시 넘겨 주어 퀴즈를 완료합니다. Derp는 펜을 귀하에게 위임 한 Finnius에게 펜을 맡겼습니다.

여기서 중요한 것은 Derp가 펜 과 직접적인 관계 가 없기 때문에 펜을주지 않는다는 것입니다.

이것은 프로토 타입의 작동 방식에 대한 간단한 예이며, 원하는 데이터를 검색 할 수 있습니다.


3

__proto__ , 프로토 타입생성자 관계를 보여주는 다른 체계 : 여기에 이미지 설명을 입력하십시오


1

이미 객체가 Object.new있지만 생성자 구문을 사용할 때 여전히 객체가 없습니다.


1

객체의 프로토 타입 (제공 Object.getPrototypeOf(obj)되지 않거나 더 이상 사용되지 않는 __proto__속성을 통해 사용 가능 )과 prototype생성자 함수 의 속성 사이에는 차이가 있다는 것을 이해하는 것이 중요 합니다. 전자는 각 인스턴스의 속성이고 후자는 생성자의 속성입니다. 즉, Object.getPrototypeOf(new Foobar())와 동일한 객체를 나타냅니다 Foobar.prototype.

참조 : https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes


0

프로토 타입 생성 새로운 객체를 기존 복제하여 개체를 . 실제로 프로토 타입에 대해 생각할 때 실제로 복제 하는 대신 복제하거나 무언가의 사본을 만드는 것으로 생각할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.