프로토 타입 생성자를 설정해야하는 이유는 무엇입니까?


294

에서 MDN이 문서의 상속에 대한 섹션 자바 스크립트 객체 지향 소개 , 나는 그들이 prototype.constructor를 설정주의 :

// correct the constructor pointer because it points to Person
Student.prototype.constructor = Student;  

이것이 중요한 목적에 도움이됩니까? 생략해도 되나요?


23
당신이 이것을 기쁘게 생각합니다 : 어제 같은 문서를 읽었으며 생성자를 명시 적으로 설정하는 이유에 대해 궁금했습니다.
Wylie

6
방금 이것을 지적해야했습니다.이 질문은 이제 당신이 링크 한 기사에 연결되어 있습니다!
Marie

7
아무것도 필요하지 않습니다
없음

1
subclass.prototype.constructor가리 킵니다 parent_class당신이 작성하지 않은 경우 subclass.prototype.constructor = subclass; 즉, subclass.prototype.constructor()직접 사용 하면 예기치 않은 결과가 발생합니다.
KuanYu Chu

답변:


263

항상 필요한 것은 아니지만 용도가 있습니다. 기본 Person클래스 에서 복사 메소드를 작성하려고한다고 가정하십시오 . 이처럼 :

// define the Person Class  
function Person(name) {
    this.name = name;
}  

Person.prototype.copy = function() {  
    // return new Person(this.name); // just as bad
    return new this.constructor(this.name);
};  

// define the Student class  
function Student(name) {  
    Person.call(this, name);
}  

// inherit Person  
Student.prototype = Object.create(Person.prototype);

이제 새로운 것을 만들어 Student복사하면 어떻게됩니까?

var student1 = new Student("trinth");  
console.log(student1.copy() instanceof Student); // => false

사본이의 인스턴스가 아닙니다 Student. (명확한 검사없이) Student"기본"클래스에서 사본 을 반환 할 방법이 없기 때문 입니다. 우리는 a 만 반환 할 수 있습니다 Person. 그러나 생성자를 재설정 한 경우 :

// correct the constructor pointer because it points to Person  
Student.prototype.constructor = Student;

... 모든 것이 예상대로 작동합니다.

var student1 = new Student("trinth");  
console.log(student1.copy() instanceof Student); // => true

34
참고 :이 constructor속성은 JS에서 특별한 의미가 없으므로 호출 할 수도 있습니다 bananashake. 유일한 차이점은 엔진이 자동으로 초기화이다 constructorf.prototype당신은 함수를 선언 할 때마다 f. 그러나 언제든지 덮어 쓸 수 있습니다.
user123444555621

58
@ Pumbaa80-요점을 알지만 엔진이 자동으로 초기화 constructor된다는 사실 은 정의상 JS에 특별한 의미 있음을 의미합니다.
Wayne

13
귀하가 말한 행동이 효과가있는 이유는 귀하가 return new this.constructor(this.name);대신 사용하기 때문이라는 것을 분명히하고 싶습니다 return new Person(this.name);. 이후 this.constructor는 IS Student(당신이 그것을 설정하기 때문에 기능 Student.prototype.constructor = Student;)의 copy기능은 호출 끝 Student기능을. 당신의 //just as bad의견 이 무엇인지 잘 모르겠습니다 .
CEGRD

12
@lwburk "// 나쁜 것"은 무엇을 의미합니까?
CEGRD

6
나는 그것을 얻는 것 같아요. 그러나 Student생성자가 다음과 같은 추가 인수를 추가하면 Student(name, id)어떻게 될까요? 그런 다음 copy함수 를 재정의하고 함수 Person내 에서 버전을 호출 한 다음 추가 id속성을 복사해야 합니까?
snapfractalpop

76

이것이 중요한 목적에 도움이됩니까?

예, 아니오

ES5 및 이전 버전에서는 JavaScript 자체가 constructor아무것도 사용하지 않았습니다 . 함수 prototype속성 의 기본 객체 가 가지고 있고 함수를 다시 참조하도록 정의 했습니다 . 사양의 다른 내용은 전혀 언급하지 않았습니다.

ES2015 (ES6)에서 상속 계층 구조와 관련하여 사용하기 시작했습니다. 예를 들어, 새로운 반환 약속을 만들 때 호출 한 약속 Promise#thenconstructor속성 ( SpeciesConstructor 를 통해 )을 사용합니다. 또한 ArraySpeciesCreate 를 통해 배열의 서브 타이핑에 관여 합니다.

언어 자체 이외에도 사람들은 일반적인 "복제"함수를 만들려고 할 때 또는 일반적으로 객체의 생성자 함수라고 생각되는 것을 참조하려고 할 때이를 사용합니다. 내 경험은 그것을 사용하는 것이 드물지만 때로는 사람들이 사용한다는 것입니다.

생략해도 되나요?

기본적으로 존재 하며 함수의 속성 에서 객체 를 교체 할 때만 다시 넣어야합니다 prototype.

Student.prototype = Object.create(Person.prototype);

이 작업을 수행하지 않으면 :

Student.prototype.constructor = Student;

... (아마도)이 가지고있는 것을 Student.prototype.constructor상속받습니다 . 오해의 소지가 있습니다. 물론,을 사용 하지 않는 ( 또는 같은 ) 그것을 사용하는 것을 서브 클래스 화하고 ¹ (이를 처리하는)을 사용하는 경우 올바르게 설정해야합니다. 기본적으로 : 좋은 생각입니다.Person.prototypeconstructor = PersonPromiseArrayclass

코드 (또는 사용하는 라이브러리 코드)에서 아무것도 사용하지 않으면 괜찮습니다. 항상 올바르게 연결되었는지 확인했습니다.

물론 ES2015 (일명 ES6)의 class키워드를 사용하면 대부분 키워드를 사용했을 때 더 이상 필요하지 않습니다.

class Student extends Person {
}

¹ "... 당신은 (같은 용도를 뭔가를 서브 클래스 화하는 경우 Promise또는 Array)가 아닌 사용 class..."  - 그건 가능한 그렇게하지만 진짜 고통 (그리고 약간 바보). 를 사용해야 Reflect.construct합니다.


12

TLDR; 꼭 필요한 것은 아니지만 장기적으로 도움이 될 것이므로 그렇게하는 것이 더 정확합니다.

참고 : 이전 답변이 혼란스럽게 작성되어 신속하게 답변을 놓치면 누락 된 부분이 많으므로 편집 한 내용이 많이 있습니다. 심각한 오류를 지적한 사람들에게 감사합니다.

기본적으로 Javascript에서 하위 클래스를 올바르게 연결합니다. 서브 클래 싱 할 때 prototype객체 덮어 쓰기를 포함하여 프로토 타입 위임이 올바르게 작동하는지 확인하기 위해 펑키 한 작업을 수행해야 합니다. prototype객체를 덮어 쓰면에가 포함 constructor되므로 참조를 수정해야합니다.

ES5의 '클래스'작동 방식을 빠르게 살펴 보겠습니다.

생성자 함수와 프로토 타입이 있다고 가정 해 봅시다.

//Constructor Function
var Person = function(name, age) {
  this.name = name;
  this.age = age;
}

//Prototype Object - shared between all instances of Person
Person.prototype = {
  species: 'human',
}

인스턴스화하기 위해 생성자를 호출하면 다음과 같이 말합니다 Adam.

// instantiate using the 'new' keyword
var adam = new Person('Adam', 19);

new'Person'으로 호출 된 키워드는 기본적으로 몇 가지 추가 코드 행으로 Person 생성자를 실행합니다.

function Person (name, age) {
  // This additional line is automatically added by the keyword 'new'
  // it sets up the relationship between the instance and the prototype object
  // So that the instance will delegate to the Prototype object
  this = Object.create(Person.prototype);

  this.name = name;
  this.age = age;

  return this;
}

/* So 'adam' will be an object that looks like this:
 * {
 *   name: 'Adam',
 *   age: 19
 * }
 */

우리 경우 console.log(adam.species), 조회가 실패 할 adam경우, 그에게 프로토 타입 체인을 찾아 볼 .prototype것입니다, Person.prototype- 그리고 Person.prototype .species 조회가에서 성공할 수 있도록 속성을 Person.prototype. 그런 다음로 기록 'human'됩니다.

여기에서는 Person.prototype.constructor을 올바르게 가리 킵니다 Person.

이제 흥미로운 부분은 소위 '서브 클래 싱'입니다. Student클래스, 즉 Person추가 변경 사항 이있는 클래스의 하위 클래스 를 만들려면 Student.prototype.constructor정확성을 위해 학생을 가리켜 야합니다.

자체적으로는이 작업을 수행하지 않습니다. 서브 클래 싱 할 때 코드는 다음과 같습니다.

var Student = function(name, age, school) {
 // Calls the 'super' class, as every student is an instance of a Person
 Person.call(this, name, age);
 // This is what makes the Student instances different
 this.school = school
}

var eve = new Student('Eve', 20, 'UCSF');

console.log(Student.prototype); // this will be an empty object: {}

new Student()여기서 호출 하면 원하는 모든 속성을 가진 객체가 반환됩니다. 여기서 확인 eve instanceof Person하면을 반환 false합니다. 액세스하려고하면 eve.species반환 undefined됩니다.

즉, 우리는 그렇게 위임을 연결할 필요가 eve instanceof Persontrue를 반환하고 그래서의 경우 Student제대로 위임에 Student.prototype다음 Person.prototype.

그러나 new키워드로 호출하기 때문에 호출이 추가하는 것을 기억하십니까? 그것은 부를 것이다 Object.create(Student.prototype)우리는 사이 delegational 관계를 설정하는 방법이다, Student하고 Student.prototype. 지금 Student.prototype은 비어 있습니다. 찾는 지금 .species의 인스턴스 Student에 위임하고 있기 때문에 실패 Student.prototype 하고 .species속성에 존재하지 않습니다 Student.prototype.

에 할당 Student.prototype하면 Object.create(Person.prototype)Student.prototype자체를 위임하면 예상대로 Person.prototype조회 eve.species가 반환 human됩니다. 아마도 우리는 그것이 Student.prototype AND Person.prototype에서 상속 받기를 원할 것입니다. 그래서 우리는 그 모든 것을 고쳐야합니다.

/* This sets up the prototypal delegation correctly 
 *so that if a lookup fails on Student.prototype, it would delegate to Person's .prototype
 *This also allows us to add more things to Student.prototype 
 *that Person.prototype may not have
 *So now a failed lookup on an instance of Student 
 *will first look at Student.prototype, 
 *and failing that, go to Person.prototype (and failing /that/, where do we think it'll go?)
*/
Student.prototype = Object.create(Person.prototype);

이제 대표단은 작동하지만, 우리는 덮어 쓰기하고 Student.prototype의와 함께 Person.prototype. 우리가 호출 Student.prototype.constructor하면 Person대신에 가리킬 것입니다 Student. 이것은 우리가 그것을 해결하기 위해 필요한 이유입니다.

// Now we fix what the .constructor property is pointing to    
Student.prototype.constructor = Student

// If we check instanceof here
console.log(eve instanceof Person) // true

ES5에서 우리의 constructor속성은 '생성자'라는 의도로 작성한 함수를 참조하는 참조입니다. new키워드가 제공 하는 것 외에도 생성자는 '일반'함수입니다.

ES6에서는 constructor이제 클래스를 작성하는 방식에 내장되어 있습니다. 클래스를 선언 할 때 메소드로 제공됩니다. 이것은 단순히 구문 설탕이지만 super기존 클래스를 확장 할 때 액세스 할 수있는 것과 같은 편의를 제공합니다 . 따라서 위 코드를 다음과 같이 작성합니다.

class Person {
  // constructor function here
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  // static getter instead of a static property
  static get species() {
    return 'human';
  }
}

class Student extends Person {
   constructor(name, age, school) {
      // calling the superclass constructor
      super(name, age);
      this.school = school;
   }
}

eve instanceof Student을 반환했습니다 true. 설명 은 stackoverflow.com/questions/35537995/… 를 참조하십시오 . 또한 당신이 which is, at the moment, nothing무엇 을 말하는가 ? 모든 기능에는 프로토 타입이 있으므로 확인 Student.prototype하면 무언가입니다.
Aseem Bansal

내 실수. false를 리턴하는 'eve instanceof Person'을 읽었어야합니다. 그 부분을 수정하겠습니다. 모든 함수에 프로토 타입 속성이있는 것이 맞습니다. 그러나 ,에 프로토 타입을 지정하지 않고 Object.create(Person.prototype)는이 Student.prototype비어 있습니다. 따라서 로그하면 eve.species수퍼 클래스 Person에 올바르게 위임되지 않으며 로그되지 않습니다 'human'. 아마도 모든 서브 클래스가 프로토 타입과 수퍼 프로토 타입에서 상속 받기를 원할 것입니다.
bthehuman

명확히하기 위해, which is, at the moment, nothing나는 Student.prototype객체가 비어 있음을 의미했습니다 .
bthehuman

프로토 타입에 대한 자세한 내용 : Student.prototypeto를 할당하지 않으면 Object.create(Person.prototype), 즉, 기억하면 Person의 모든 인스턴스 가 위임 할 Person.prototype인스턴스의 속성을 조회 하도록 위임하는 것과 동일한 방식으로 Person의 모든 인스턴스 Student가 위임 됩니다 Student.prototype . 따라서 eve.species조회에 실패합니다. 우리가 그것을 할당하면, Student.prototype그 자체로에 위임하고 Person.prototype, 조회는를 eve.species반환 할 것 human입니다.
bthehuman

"instance 여기서 '서브 클래 싱'[...]을 에뮬레이션하려고 할 때 필요하므로 인스턴스가 '서브 클래스'생성자 인지 확인할 때 정확해야합니다." 아니, instanceof사용하지 않습니다 constructor. "그러나 우리가 학생의 .prototype.constructor를 찾아 보면 여전히 Person을 가리킬 것입니다 Student." 이 예제의 요점을 이해하지 못합니다. 생성자에서 함수를 호출하는 것은 상속이 아닙니다. "ES6에서 생성자는 이제 함수에 대한 참조 대신 실제 함수입니다" 어?
Felix Kling

10

동의하지 않습니다. 프로토 타입을 설정할 필요는 없습니다. 정확히 동일한 코드를 사용하지만 prototype.constructor 줄을 제거하십시오. 변화가 있습니까? 아니요. 이제 다음과 같이 변경하십시오.

Person = function () {
    this.favoriteColor = 'black';
}

Student = function () {
    Person.call(this);
    this.favoriteColor = 'blue';
}

그리고 테스트 코드의 끝에서 ...

alert(student1.favoriteColor);

색상은 파란색입니다.

내 경험상 prototype.constructor의 변경은 어쨌든 모범 사례가 아닌 매우 구체적이고 복잡한 작업을 수행하지 않는 한 많이하지 않습니다. :)

편집 : 웹을 조금 둘러보고 실험을 한 후에 사람들이 생성자를 '신규'로 구성되는 것과 같이 보이도록 생성자를 설정 한 것처럼 보입니다. 나는 이것에 대한 문제가 자바 스크립트가 프로토 타입 언어라는 것입니다-상속과 같은 것은 없습니다. 그러나 대부분의 프로그래머는 상속을 '길'로 밀어 넣는 프로그래밍의 배경을 가지고 있습니다. 그래서 우리는이 프로토 타입 언어를 '클래스'언어와 같은 '클래스'확장과 같은 시도하고 시도 할 모든 종류의 것들을 생각해 냈습니다. 실제로 그들이 제시 한 예에서, 새로운 학생은 사람입니다 – 그것은 다른 학생으로부터 '확장'되지 않습니다. 학생은 그 사람에 관한 것입니다. 학생, 그리고 당신이 무엇이든 연장

Crockford는 약간 미쳤고 지나치게 열성적이지만, 그가 쓴 것들 중 일부에 대해 진지한 독서를합니다.


8
이것은 프로토 타입 체인을 상속하지 않습니다.
Cypher

1
@Cypher 느린 박수 는 4 년 후 대화에 오신 것을 환영합니다. 예 . prototype.constructor를 덮어 쓰는지 여부에 관계없이 프로토 타입 체인 상속됩니다. 그것을 시험해보십시오.
Stephen

7
프로토 타입을 상속하는 코드가 없습니다. 인터넷에 오신 것을 환영합니다.
Cypher

1
@Cypher Code 스 니펫은 링크 된 기사의 코드를 기반으로했습니다. 질문 전체를 읽은 것을 환영합니다. 오. 기다림.
Stephen

1
@macher 나는 고전적인 상속이라고 생각했다. 내 말로 표현의 가난한 선택.
Stephen

9

이것은 당신이 쓴다면 큰 함정이 있습니다

Student.prototype.constructor = Student;

그러나 그 프로토 타입이 Person 인 교사가 있다면

Teacher.prototype.constructor = Teacher;

학생 생성자는 이제 교사입니다!

편집 : Mozilla 예제에서와 같이 Object.create를 사용하여 작성된 Person 클래스의 새 인스턴스를 사용하여 Student 및 Teacher 프로토 타입을 설정하여이를 방지 할 수 있습니다.

Student.prototype = Object.create(Person.prototype);
Teacher.prototype = Object.create(Person.prototype);

1
Student.prototype = Object.create(...)이 질문에서 가정합니다. 이 답변은 가능한 혼란을 추가합니다.
André Chalella 21시 14 분

3
@ AndréNeves이 답변이 도움이되었다는 것을 알았습니다. Object.create(...)는 질문을 생성 한 MDN 기사에서 사용되지만 질문 자체에서는 사용되지 않습니다. 많은 사람들이 클릭 연결을하지 않을 것이라고 확신합니다.
Alex Ross

질문에서 참조 된 링크 된 기사는 Object.create ()를 사용합니다. 이 답변과 그 답변의 편집은 실제로 관련이 없으며 가장 덜 말하기는 혼란 스럽습니다 :-)
Drenai

1
더 넓은 요점은 사람들에게 Javascript 프로토 타입을 처음 접하게되는 문제가 있다는 것입니다. 2016 년에 논의 할 경우 실제로 ES6 클래스, Babel 및 / 또는 Typescript를 사용해야합니다. 그러나 이런 식으로 클래스를 수동으로 구성하려는 경우 프로토 타입 체인이 실제로 그 힘을 활용하는 방법을 이해하는 데 도움이됩니다. 객체를 프로토 타입으로 사용할 수 있으며 별도의 객체를 새로 만들고 싶지 않을 수도 있습니다. 또한 HTML 5가 완전히 널리 보급되기 전에는 Object.create를 항상 사용할 수 없었으므로 클래스를 잘못 설정하는 것이 더 쉬웠습니다.
James D

5

지금까지 혼란은 여전히 ​​있습니다.

기존 예제를 따르면 다음과 같은 기존 오브젝트 student1가 있습니다.

var student1 = new Student("Janet", "Applied Physics");

어떻게 student1생성 되는지 알고 싶지 않다고 가정 하고 다른 객체를 원하면 like의 constructor 속성을 사용할 수 있습니다 student1.

var student2 = new student1.constructor("Mark", "Object-Oriented JavaScript");

여기서 Student생성자 속성이 설정되어 있지 않으면 속성을 가져 오지 못합니다. 오히려 Person객체 를 생성 합니다.


2

프로토 타입 생성자를 설정해야하는 이유에 대한 좋은 코드 예제가 있습니다.

function CarFactory(name){ 
   this.name=name;  
} 
CarFactory.prototype.CreateNewCar = function(){ 
    return new this.constructor("New Car "+ this.name); 
} 
CarFactory.prototype.toString=function(){ 
    return 'Car Factory ' + this.name;
} 

AudiFactory.prototype = new CarFactory();      // Here's where the inheritance occurs 
AudiFactory.prototype.constructor=AudiFactory;       // Otherwise instances of Audi would have a constructor of Car 

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

AudiFactory.prototype.toString=function(){ 
    return 'Audi Factory ' + this.name;
} 

var myAudiFactory = new AudiFactory('');
  alert('Hay your new ' + myAudiFactory + ' is ready.. Start Producing new audi cars !!! ');            

var newCar =  myAudiFactory.CreateNewCar(); // calls a method inherited from CarFactory 
alert(newCar); 

/*
Without resetting prototype constructor back to instance, new cars will not come from New Audi factory, Instead it will come from car factory ( base class )..   Dont we want our new car from Audi factory ???? 
*/

당신의 createNewCar방법은 공장을 만드는 것입니다!? 또한 이것은 var audiFactory = new CarFactory("Audi")상속을 사용하는 것이 아니라 사용해야했던 것처럼 보입니다 .
Bergi

귀하의 예제는 this.constructor내부적 으로 사용 되므로 설정해야한다는 것은 놀라운 일이 아닙니다. 그것없이 예가 있습니까?
Dmitri Zaitsev

1

요즘 설탕 함수 '클래스'또는 '신규'를 사용할 필요가 없습니다. 객체 리터럴을 사용하십시오.

Object 프로토 타입은 이미 '클래스'입니다. 객체 리터럴을 정의하면 이미 프로토 타입 객체의 인스턴스입니다. 이것들은 다른 객체의 프로토 타입 등으로 작동 할 수도 있습니다.

const Person = {
  name: '[Person.name]',
  greeting: function() {
    console.log( `My name is ${ this.name || '[Name not assigned]' }` );
  }
};
// Person.greeting = function() {...} // or define outside the obj if you must

// Object.create version
const john = Object.create( Person );
john.name = 'John';
console.log( john.name ); // John
john.greeting(); // My name is John 
// Define new greeting method
john.greeting = function() {
    console.log( `Hi, my name is ${ this.name }` )
};
john.greeting(); // Hi, my name is John

// Object.assign version
const jane = Object.assign( Person, { name: 'Jane' } );
console.log( jane.name ); // Jane
// Original greeting
jane.greeting(); // My name is Jane 

// Original Person obj is unaffected
console.log( Person.name ); // [Person.name]
console.log( Person.greeting() ); // My name is [Person.name]

이것은 읽을만한 가치가 있습니다 .

Java 및 C ++와 같은 클래스 기반 객체 지향 언어는 클래스와 인스턴스라는 두 가지 엔티티의 개념을 기반으로합니다.

...

JavaScript와 같은 프로토 타입 기반 언어는 이러한 차이점을 만들지 않습니다. 단순히 객체 만 있습니다. 프로토 타입 기반 언어에는 프로토 타입 객체라는 개념이 있는데,이 객체는 새 객체의 초기 속성을 가져 오는 템플릿으로 사용됩니다. 모든 객체는 객체를 만들거나 런타임에 고유 한 속성을 지정할 수 있습니다. 또한 모든 객체를 다른 객체의 프로토 타입으로 연결할 수 있으므로 두 번째 객체가 첫 번째 객체의 속성을 공유 할 수 있습니다


1

toStringmonkeypatching없이 대안을 필요로 할 때 필요합니다 :

//Local
foo = [];
foo.toUpperCase = String(foo).toUpperCase;
foo.push("a");
foo.toUpperCase();

//Global
foo = [];
window.toUpperCase = function (obj) {return String(obj).toUpperCase();}
foo.push("a");
toUpperCase(foo);

//Prototype
foo = [];
Array.prototype.toUpperCase = String.prototype.toUpperCase;
foo.push("a");
foo.toUpperCase();

//toString alternative via Prototype constructor
foo = [];
Array.prototype.constructor = String.prototype.toUpperCase;
foo.push("a,b");
foo.constructor();

//toString override
var foo = [];
foo.push("a");
var bar = String(foo);
foo.toString = function() { return bar.toUpperCase(); }
foo.toString();

//Object prototype as a function
Math.prototype = function(char){return Math.prototype[char]};
Math.prototype.constructor = function() 
  {
  var i = 0, unicode = {}, zero_padding = "0000", max = 9999;
  
  while (i < max) 
    {
    Math.prototype[String.fromCharCode(parseInt(i, 16))] = ("u" + zero_padding + i).substr(-4);

    i = i + 1;
    }    
  }

Math.prototype.constructor();
console.log(Math.prototype("a") );
console.log(Math.prototype["a"] );
console.log(Math.prototype("a") === Math.prototype["a"]);


무엇을해야합니까? foo.constructor()??
Ry-

0

편집, 나는 실제로 틀렸다. 줄을 주석 처리해도 동작이 전혀 바뀌지 않습니다. (테스트했습니다)


예, 필요합니다. 당신이 할 때

Student.prototype = new Person();  

Student.prototype.constructor됩니다 Person. 따라서 호출 Student()하면에 의해 생성 된 객체가 반환됩니다 Person. 당신이 그렇다면

Student.prototype.constructor = Student; 

Student.prototype.constructor로 다시 재설정됩니다 Student. 이제 호출하면 부모 생성자 를 호출 Student()하는 executes 가 올바르게 상속 된 객체를 반환합니다. 호출하기 전에 재설정하지 않으면 속성이 설정되지 않은 객체가 표시됩니다 .StudentParent()Student.prototype.constructorStudent()


3
프로토 타입 구조는 사람이 될 수 있지만, 사람으로부터 모든 속성과 방법을 상속하기 때문에 적절합니다. prototype.constructor를 설정하지 않고 새 Student ()를 만들면 자체 생성자를 적절하게 호출합니다.
Stephen

0

주어진 간단한 생성자 함수 :

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


console.log(Person.prototype.constructor) // function Person(){...}

Person.prototype = { //constructor in this case is Object
    sayName: function(){
        return this.name;
    }
}

var person = new Person();
console.log(person instanceof Person); //true
console.log(person.sayName()); //test
console.log(Person.prototype.constructor) // function Object(){...}

기본적으로 ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor 사양에서 ) 모든 프로토 타입은 자동으로 생성자라는 속성을 가져옵니다. 그것은 속성입니다. 생성자에 따라 다른 속성 및 메서드가 프로토 타입에 추가 될 수 있으며 이는 일반적이지 않지만 확장이 허용됩니다.

따라서 간단하게 대답 : 우리는 prototype.constructor의 값이 사양에서 가정 한대로 올바르게 설정되어 있는지 확인해야합니다.

이 값을 항상 올바르게 설정해야합니까? 디버깅에 도움을주고 내부 구조를 사양과 일관성있게 만듭니다. 우리는 API가 제 3 자에 의해 사용될 때 확실해야하지만 실제로 런타임에 코드가 실행될 때가 아닙니다.


0

다음은 MDN의 사용법을 이해하는 데 매우 유용한 예제입니다.

JavaScript에는 AsyncFunction 객체 async functions를 반환하는 것이 있습니다 . 전역 객체는 아니지만 속성 을 사용하여 검색하여 활용할 수 있습니다.AsyncFunctionconstructor

function resolveAfter2Seconds(x) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(x);
    }, 2000);
  });
}

// AsyncFunction constructor
var AsyncFunction = Object.getPrototypeOf(async function(){}).constructor

var a = new AsyncFunction('a', 
                          'b', 
                          'return await resolveAfter2Seconds(a) + await resolveAfter2Seconds(b);');

a(10, 20).then(v => {
  console.log(v); // prints 30 after 4 seconds
});

-1

필요하지 않습니다. 이는 OOP 챔피언이 전통적으로 자바 스크립트의 프로토 타입 상속을 클래식 상속으로 전환하려고하는 많은 일 중 하나 일뿐입니다. 다음과 같은 유일한 것

Student.prototype.constructor = Student; 

현재의 "생성자"에 대한 참조가 생겼다는 것입니다.

Wayne의 답변에서 올바른 것으로 표시되어 있으므로 다음 코드와 동일한 기능을 수행 할 수 있습니다

Person.prototype.copy = function() {  
    // return new Person(this.name); // just as bad
    return new this.constructor(this.name);
};  

아래 코드로 (this.constructor를 Person으로 바꾸십시오)

Person.prototype.copy = function() {  
    // return new Person(this.name); // just as bad
    return new Person(this.name);
}; 

ES6 고전 상속을 통해 순수 주의자들은 클래스, 확장 및 수퍼와 같은 언어의 기본 연산자를 사용할 수 있으며 우리는 prototype.constructor 수정 및 부모 심판과 같이 볼 필요가 없습니다.

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