Чому потрібно встановлювати конструктор прототипу?


294

У розділі про успадкування у статті MDN Введення в об'єктно-орієнтований Javascript я помітив, що вони встановили прототип.конструктор:

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

Чи служить це якійсь важливій меті? Чи добре це пропустити?


23
Радий, що ви запитали це: я читав ту саму документацію вчора і мені цікаво міркувати про те, як явно встановити конструктор.
Wylie

6
Я просто мусив це зазначити, це питання тепер пов'язане у статті, яку ви пов’язали!
Марі

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. Єдина відмінність полягає в тому , що двигун автоматично ініціалізує constructorна f.prototypeвсякий раз , коли ви оголошуєте функцію f. Однак його можна перезаписати будь-коли.
користувач123444555621

58
@ Pumbaa80 - я отримую вашу точку, але той факт , що двигун автоматично ініціалізує constructorозначає , що вона робить мають особливе значення в JS, в значній мірі за визначенням.
Уейн

13
Я просто хочу уточнити, що причина поведінки, яку ви сказали, полягає в тому, що ви використовуєте return new this.constructor(this.name);замість цього return new Person(this.name);. Оскільки this.constructorце 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#thenвикористовує constructorвластивість обіцянки, яку ви її закликаєте (через SpeciesConstructor ), будуючи нову обіцянку повернення. Він також бере участь у підтипуванні масивів (через ArraySpeciesCreate ).

Поза самою мовою люди іноді використовували б її, намагаючись побудувати загальні функції "клонування" або просто загалом, коли вони хотіли посилатися на те, що вони вважали, що це конструкторська функція об'єкта. Мій досвід полягає в тому, що користуватися ним рідко, але іноді люди користуються ним.

Чи добре це пропустити?

Він там за замовчуванням, його потрібно повернути лише під час заміни об'єкта на prototypeвластивість функції :

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

Якщо цього не зробити:

Student.prototype.constructor = Student;

... то Student.prototype.constructorуспадковує, від Person.prototypeчого (імовірно) має constructor = Person. Тож це вводить в оману. І звичайно, якщо ви підкласифікуєте щось, що використовує його (наприклад, Promiseабо Array), а ви не використовуєте class¹ (що обробляє це для вас), вам потрібно переконатися, що ви його правильно встановили. Так в основному: це гарна ідея.

Добре, якщо у вашому коді (або бібліотечному коді, який ви використовуєте) нічого не використовується. Я завжди переконався, що це правильно підключено.

Звичайно, що за ключовим словом 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 з декількома додатковими рядками коду:

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 Personповертав істину і таким чином, щоб екземпляри Studentделегували правильно до Student.prototype, а потім Person.prototype.

Але, оскільки ми називаємо це newключовим словом, пам’ятайте, що додає ця виклик? Це закликає Object.create(Student.prototype), саме так ми встановлювали відносини делегації між 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тепер вбудований у спосіб, коли ми пишемо класи - як у, він надається як метод, коли ми оголошуємо клас. Це просто синтаксичний цукор, але він надає нам деякі зручності, такі як доступ до a, 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це щось.
Асеем Бансал

Моя помилка. Він повинен був прочитати "напередодні Особи", що поверне помилкове значення. Я виправляю цю частину. Ви вірні, що кожна функція має властивість прототипу. Однак , не привласнюючи прототип Object.create(Person.prototype), значення Student.prototypeпорожнє. Отже, якщо ми входимо в систему eve.species, він не буде належним чином делегувати до свого суперкласу, Person, і він не буде реєструватися 'human'. Імовірно, ми хочемо, щоб кожен підклас успадкував від свого прототипу, а також прототип свого супер.
bthehuman

Щоб уточнити, which is, at the moment, nothingя мав на увазі, що Student.prototypeоб’єкт порожній.
bthehuman

Детальніше про прототип: Без присвоєння Student.prototypeдо Object.create(Person.prototype)- що, якщо ви пам’ятаєте, однаково, всі екземпляри Person створені для делегування до Person.prototype- пошуку властивості за екземпляром, який Studentби делегувався лише Student.prototype . Так eve.speciesне вдасться його знайти. Якщо ми все-таки призначимо його, Student.prototypeтоді делегати Person.prototype, і дивлячись eve.species, повернуться human.
bthehuman

Здається, тут є щось неправильне: "Це необхідно, коли ви намагаєтеся емулювати" підкласифікацію "[...], так що коли ви перевіряєте, чи екземпляр є instanceконструктором" підкласу ", він буде точним". Ні, instanceofне використовує constructor. "Однак, якщо ми подивимось на .prototype.constructor студента, він все одно вказуватиме на Особу" Ні, це буде Student. Я не розумію сенсу цього прикладу. Виклик функції в конструкторі - це не спадкування. "У ES6 конструктор тепер є фактичною функцією замість посилання на функцію .
Фелікс Клінг

10

Я б не погодився. Не потрібно встановлювати прототип. Візьміть такий самий код, але видаліть рядок prototype.constructor. Чи щось змінюється? Ні. Тепер внесіть такі зміни:

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

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

і в кінці тестового коду ...

alert(student1.favoriteColor);

Колір буде синім.

Зміна мого прототипу.constructor, на мій досвід, не робить багато, якщо ви робите дуже конкретні, дуже складні речі, які, мабуть, не є хорошою практикою :)

Редагувати: Після того, як трохи покататись в Інтернеті та зробити кілька експериментів, схоже, що люди встановили конструктор так, щоб він виглядав як те, що будується з «нового». Я думаю, я б заперечував, що проблема в тому, що javascript є мовою прототипу - не існує такого поняття, як успадкування. Але більшість програмістів походять з фону програмування, що висуває спадщину як "шлях". Тож ми придумуємо всілякі речі, щоб спробувати перетворити цю прототипну мову на "класичну" мову, наприклад, на розширення "класів". Дійсно, у прикладі, який вони наводили, новий студент - це людина - це не "продовження" від іншого студента. Учень все про людину, і що б там не було. Розширюйте студента і що б ви не хотіли "

Крокфорд трохи божевільний і надмірний, але серйозно читайте деякі речі, які він написав .. це змусить вас поглянути на цей матеріал зовсім інакше.


8
Це не успадковує ланцюг прототипу.
Cypher

1
@Cypher повільно хлопає ласкаво просимо до розмови через чотири роки. Так, ланцюжок прототипів буде успадкований, незалежно від того, ви перезаписати чи в prototype.constructor. Спробуйте випробувати його.
Стівен

7
Вам не вистачає коду, який успадковує прототип. Ласкаво просимо в Інтернет.
Cypher

1
Фрагмент @Cypher Code був заснований на коді у пов'язаній статті. Ласкаво просимо до прочитання питання в повному обсязі. Ой. Зачекайте.
Стівен

1
@macher Я мав на увазі це як класичне успадкування. Поганий вибір формулювань з мого боку.
Стівен

9

Це величезний підводний камінь, який, якби ти писав

Student.prototype.constructor = Student;

але тоді, якщо був Вчитель, прототипом якого також була Особа, і ви писали

Teacher.prototype.constructor = Teacher;

тоді конструктор Студент - зараз Вчитель!

Редагувати: Ви можете цього уникнути, переконавшись, що ви встановили прототипи Student and Teacher, використовуючи нові екземпляри класу Person, створені за допомогою Object.create, як у прикладі Mozilla.

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

1
Student.prototype = Object.create(...)В цьому питанні передбачається. Ця відповідь не додає нічого, крім можливої ​​плутанини.
Андре Шалелла

3
@ AndréNeves Я вважаю цю відповідь корисною. Object.create(...)використовується в статті MDN, яка породила питання, але не в самому питанні. Я впевнений, що багато людей не натискають.
Алекс Росс

Пов'язана стаття, на яку посилається у алфайі питань, використовує Object.create (). Ця відповідь та Редагування відповіді не дуже актуальні, і щонайменше заплутано :-)
Дреней

1
Більш широкий сенс полягає в тому, що є ґазди, які дозволять обробляти людей новими прототипами Javascript. Якщо ми обговорюємо в 2016 році, то вам дійсно слід використовувати класи ES6, Babel та / або Typescript. Але якщо ви дійсно хочете вручну побудувати класи таким чином, це допоможе зрозуміти, як прототипи ланцюгів дійсно працюють, щоб використовувати їх силу. Ви можете використовувати будь-який об’єкт в якості прототипу, і, можливо, ви не хочете створювати новий окремий об'єкт. Крім того, ще до того, як HTML 5 отримав повне розповсюдження, Object.create не завжди був доступний, тому було легше встановити клас неправильно.
Джеймс Д

5

Поки плутанина все ще існує.

Виходячи з оригінального прикладу, як у вас є існуючий об'єкт student1як:

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

Припустимо, ви не хочете знати, як student1створено, ви просто хочете інший об’єкт, як він, ви можете використовувати властивість конструктора 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")замість спадкування.
Бергі

Ваш приклад використовується this.constructorвнутрішньо, тому не дивно, що його потрібно встановити. У вас є приклад без нього?
Дмитро Зайцев

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

Це необхідно, коли вам потрібна альтернатива toStringбез маніпулювання:

//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()??
Ри-

0

EDIT, я насправді помилявся. Коментування рядка зовсім не змінює його поведінку. (Я перевірив це)


Так, це необхідно. Коли ви робите

Student.prototype = new Person();  

Student.prototype.constructorстає Person. Отже, виклик Student()поверне об'єкт, створений Person. Якщо ви тоді

Student.prototype.constructor = Student; 

Student.prototype.constructor повертається до Student . Тепер, коли ви викликаєте Student()його виконання Student, яке викликає батьківський конструктор Parent(), він повертає правильно успадкований об'єкт. Якщо ви не скинули його Student.prototype.constructorперед тим, як викликати його, ви отримаєте об'єкт, який би не мав жодного з встановлених властивостей Student().


3
Конструкція прототипу може стати людиною, але це доречно, оскільки вона успадковує всі властивості та методи від Особи. Створення нового Student () без встановлення prototype.constructor належним чином викликає власний конструктор.
Стівен

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 використовуються третіми сторонами, але не дуже, коли код остаточно виконується під час виконання.


0

Ось один приклад з MDN, який мені здався дуже корисним для розуміння його використання.

У JavaScript ми маємо async functionsякий повертає об’єкт AsyncFunction . AsyncFunctionне є глобальним об'єктом, але його можна отримати за допомогою constructorвластивості та використовувати його.

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 намагаються перетворити прототипне успадкування JavaScript у класичне успадкування. Єдине, що наступне

Student.prototype.constructor = Student; 

це, це те, що тепер у вас є посилання на поточний "конструктор".

У відповіді Уейна, що було позначено як правильне, ви могли б точно сказати наступний код

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

з кодом нижче (просто замініть цей.конструктор на Person)

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

Слава Богу, що з класичними елементами успадкування ES6 можуть використовувати вродні оператори мови, такі як клас, розширення та супер, і нам не доведеться бачити виправлення прототипу.конструктора та батьківські судження.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.