Питання Як працює JavaScript-прототип?


Я не в тому, що в динамічні мови програмування, але я написав свою частку коду JavaScript. Я ніколи не мав своєї голови навколо цього прототипу-основі програмування, чи хтось знає, як це працює?

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

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

Але яка конкретна мета цього .prototype властивість у JavaScript? Як це стосується екземплярів об'єктів?


Редагувати

Ці слайди дуже допомогло зрозуміти цю тему.


1858
2018-02-21 12:31


походження


Джон Ресіг має декілька слайдів про прототипи функцій, які були мені корисні під час перегляду теми (ви також можете внести зміни в код і подивитися, що станеться ...) http://ejohn.org/apps/learn/#64 - John Foster
Великий довідковий матеріал, з метою збереження цього питання інформативним, можливо, розмістити деякі коментарі з сайту Джона на вашу відповідь, якщо його сайт зміниться так, що ваша посилання більше не доступна. У будь-якому випадку +1 допомогло мені. - Chris
+1 для вашої посилання на Слайд №67 JavaScript Ninja Джона Резіга. Починаючи звідти було дуже корисним, і я відчуваю, що я правильно розумію прототипи. - a paid nerd
Чи дійсно нам потрібен функціональний об'єкт для застосування прототипу? якщо так, то чому? - Anshul
Це може допомогти вам: webdeveasy.com/javascript-прототип - Naor


Відповіді:


Кожен об'єкт JavaScript має внутрішню властивість [[Прототип]]. Якщо ви шукаєте властивість через obj.propName або obj['propName'] і об'єкт не має такої властивості - яку можна перевірити через obj.hasOwnProperty('propName') - runtime шукає властивість об'єкта, на який посилається [[Prototype]] замість. Якщо об'єкт прототипу також не має такої властивості, його прототип перевіряється по черзі, таким чином ходьба оригінального об'єкта прототип-ланцюг поки не знайдено матч або його кінець не досягнуто.

Деякі реалії JavaScript дозволяють отримати прямий доступ до властивості [[Prototype]], наприклад, через нестандартну властивість, названу __proto__. Загалом, під час створення об'єкта можна встановити лише прототип об'єкта: якщо ви створюєте новий об'єкт через new Func(), властивість [[Prototype]] об'єкта буде встановлено на об'єкт, на який посилається Func.prototype.

Це дозволяє імітувати класи у JavaScript, хоча система успадкування JavaScript - як ми бачили - є прототипом, а не класом:

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


927
2018-02-21 13:33



Отже, я роблю щось неправильно, визначаючи нові властивості на властивості прототипу у своєму короткому фрагменті? - John Leidegren
Я думаю, що це означає мати функції об'єктів як першокласних громадян. - John Leidegren
Я ненавиджу нестандартні речі, особливо на мовах програмування, чому там навіть є Прото коли це явно не потрібне? - John Leidegren
@ H1D: якщо Class.method не знайдено, час виконання шукає Class.__proto__.method (вірніше Object.getPrototypeOf(Class).method у сумісному ES5) і ні  Class.prototype.method - Christoph
Зауважте, що використання [[Прототип]] навмисно - ECMA-262 містить назви внутрішніх властивостей з подвійними квадратними дужками - Christoph


У мові, що реалізує класичну спадщину, таку як 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();

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

//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());

var Person = function (name) {
    this.name = name;
};
Person.prototype.getName = function () {
    return this.name;
};
var john = new Person("John");
alert(john.getName());
Person.prototype.sayMyName = function () {
    alert('Hello, my name is ' + this.getName());
};
john.sayMyName();
var Customer = function (name) {
    this.name = name;
};
Customer.prototype = new Person();

var myCustomer = new Customer('Dream Inc.');
myCustomer.sayMyName();
Customer.prototype.setAmountDue = function (amountDue) {
    this.amountDue = amountDue;
};
Customer.prototype.getAmountDue = function () {
    return this.amountDue;
};
myCustomer.setAmountDue(2000);
alert(myCustomer.getAmountDue());

Хоча, як зазначено, я не можу викликати setAmountDue (), getAmountDue () у Людині.

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

1755
2018-01-24 03:42



Я думаю, що відповіді стосовно потокового потоку не тільки цікаві оригінальному плакатові, а й великій спільноті інших людей, що ховаються або йдуть від пошуків. І я був одним з них, і я мав вигоду з старих повідомлень. Я думаю, що міг би сприяти іншим відповідям, додаючи деякі приклади коду. Про ваше запитання: якщо ви вийдете з нового, це не спрацює. коли я називаю myCustomer.sayMyName (), він повертає "myCustomer.sayMyName не є функцією". Найпростіший спосіб - експериментувати з firebug і побачити, що станеться. - stivlo
Наскільки я розумію, var Person = function (name) {...}; визначає функцію конструктора, здатну будувати об'єкти Person. Таким чином, поки немає об'єкта, особі призначається лише анонімна конструкторська функція. Це дуже гарне пояснення: helephant.com/2008/08/how-javascript-objects-work - stivlo
ПОПЕРЕДЖЕННЯ. У цьому відповіді не враховується той факт, що конструктор батьківського класу не викликається на екземплярній основі. Єдина причина цього полягає в тому, що він зробив точно так само (встановивши ім'я) як у конструкторі дитини, так і у батьків. Для більш глибокого пояснення загальних помилок, зроблених при спробі спадщини в JavaScript (і остаточне рішення), див. цей стовп переповнення повідомлення - Aaren Cordova
Я помітив, що в цій відповіді також не згадується, що, використовуючи "нову особу" () як прототип, ви фактично встановлюєте властивість екземпляра "name" "Person" як статичне властивість "Клієнта" (таким чином, всі Клієнт екземпляри матимуть одне і те ж властивість). Хоча це хороший основний приклад, не робіть цього. :) Створіть нову анонімну функцію, яка слугуватиме «мостом», встановивши прототип на «Person.prototype», потім створіть екземпляр із нього і замість цього встановіть «Customer.prototype» на цей анонімний екземпляр. - James Wilkins
Про Customer.prototype = new Person(); лінія, MDN показує приклад використання Customer.prototype = Object.create(Person.prototype), і стверджує, що "Найпоширенішою помилкою тут є використання" нової людини () "". джерело - Rafael Eyng


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


Це дуже простий прототип на основі об'єктної моделі, який буде розглядатися як зразок під час пояснення, поки ще немає коментарів:

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

Є кілька важливих моментів, які ми повинні розглянути, перш ніж пройти концепцію прототипу.

1- Яким чином функції JavaScript дійсно працюють:

Щоб зробити перший крок, нам доведеться з'ясувати, наскільки функціональні функції JavaScript дійсно працюють, використовуючи функцію класу подібну this ключове слово в ньому або просто як звичайна функція з аргументами, що вона робить і що вона повертає.

Скажімо, ми хочемо створити Person об'єктна модель але на цьому кроці я буду намагатися робити ту ж саму точку без використання prototype і new ключове слово.

Отже, на цьому кроці functions, objects і this ключове слово, все це є.

Перше питання було б як this ключове слово може бути корисним без використання new ключове слово.

Отже, щоб відповісти, скажімо, у нас є порожній об'єкт і дві функції, такі як:

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

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

а зараз без використання new ключове слово як ми могли б використовувати ці функції. Отже, JavaScript має 3 різні способи зробити це:

a. Перший спосіб полягає в тому, щоб викликати функцію як звичайну функцію:

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

в цьому випадку це буде поточним об'єктом контексту, який зазвичай є глобальним window об'єкт в браузері або GLOBAL в Node.js. Це означає, що нам доведеться мати ім'я window.name в браузері або GLOBAL.name у Node.js, а "George" - це значення.

б Ми можемо прикріпити їх до об'єкта, як його властивості

-Найпростіший спосіб Для цього потрібно змінити порожній person об'єкт, як:

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

таким чином ми можемо назвати їх такими:

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

і тепер person об'єкт подібний:

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

-Інший спосіб прив'язати власність до об'єкта використовується prototype цього об'єкта, який можна знайти в будь-якому об'єкті JavaScript із назвою __proto__, і я намагався пояснити це трохи в короткій частині. Таким чином ми могли б отримати подібний результат, зробивши це:

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


2- Як працює new ключове слово працює?

це другий крок, щоб зрозуміти .prototype Це те, що я використовую для імітації процесу:

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

в цій частині я намагаюся виконувати всі кроки, які виконує JavaScript, не використовуючи new ключове слово та prototype, коли ви використовуєте new ключове слово так що коли ми робимо new Person("George"), Person Функція виконує роль конструктора. Ось що робить JavaScript, один за іншим:

a. перш за все це робить порожній об'єкт, в основному порожній хеш, як:

var newObject = {};

б наступним кроком, який виконує JavaScript прикріпити весь прототип об'єктів до нового створеного об'єкта

ми маємо my_person_prototype тут схоже на об'єкт прототипу.

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

Це не так, як JavaScript насправді надає властивості, визначені в прототипі. Фактичний спосіб пов'язаний з концепцією ланцюга прототипів.


a. & 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"]);

тоді конструктор може зробити все, що завгодно, тому що це всередині цього конструктора - це об'єкт, який тільки що був створений.

Тепер кінцевий результат перед імітацією інших кроків:     Об'єкт {ім'я: "Джордж"}


Підсумок:

В основному, коли ви використовуєте новий ключове слово на функцію, ви викликаєте це, і ця функція виконує роль конструктора, тому, коли ви говорите:

new FunctionName()

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

Отже, коли JavaScript шукає властивість на об'єкті, то перше, що він робить, - це тобі це об'єкт. І тоді є таємна властивість [[prototype]] які ми, як правило, маємо це __proto__ і це властивість - те, що JavaScript виглядає на наступний. І коли він дивиться через __proto__, оскільки вона є ще одним об'єктом JavaScript, вона має свою власну __proto__атрибут, він піднімається і вгору, поки він не досягне точки, де наступний __proto__ є нульовим. Справа є єдиним об'єктом у JavaScript, що його __proto__ атрибут null є Object.prototype об'єкт:

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

і саме так працює спадщина в JavaScript.

The prototype chain

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


163
2018-02-13 19:32



а) Будь ласка, не пояснюйте прототипи шляхом копіювання властивостей b) Встановлення внутрішнього [[прототип]] відбувається до того, як функція конструктора застосовується до екземпляра, будь-ласка, змініть це замовлення. c) jQuery цілком є ​​оффтопним в цьому питанні - Bergi
@Бергі: дякую, що натякнув, я був би вдячний, якщо ви дасте мені знати, якщо це нормально. - Mehran Hatami
Чи можете ви, будь ласка, зробити це простим? Ви маєте рацію з усіх питань, але студенти, які читають це пояснення, можуть бути дійсно заплутані вперше. підібрати будь-який простий приклад, і нехай код пояснити сам або додати купу коментарів, щоб уточнити, що ви маєте на увазі. - P.M
@ P.M: Дякуємо за відгук. Я намагався зробити це якомога простішим, але я думаю, ви маєте рацію, у нього ще є деякі невизначені моменти. Тому я намагатимусь його змінити, а також бути більш описовим. :) - Mehran Hatami
+1 для ілюстрації в кінці вашої "книги" :) - sargas


prototype дозволяє робити заняття. якщо ви не використовуєте prototype то стає статичним.

Ось короткий приклад.

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

У вищезгаданому випадку ви маєте статичний тест функціонального виклику. Цю функцію можна отримати лише за допомогою obj.test, де ви можете уявити, що obj є класом.

де як у наведеному нижче коді

function obj()
{
}

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

Об'єкт став класом, який тепер може бути екземпляром. Існує декілька об'єктів obj, і всі вони мають test функція

Вищезгадане моє розуміння. Я роблю це вікі, щоб люди могли виправити мене, якщо я помиляюсь.


66
2017-11-07 09:48



-1: prototype є властивістю функцій конструктора, а не екземплярів, тобто ваш код неправий! Можливо, ви мали на увазі нестандартну власність __proto__ об'єктів, але це зовсім інший звір ... - Christoph
@ Christoph - Дякую, що вказали на це. Я оновив код зразка. - Ramesh
Це якась хороша відповідь, але для цього є ще більше. - John Leidegren
Там набагато більше ... Плюс JavaScript не є класовою мовою - це стосується спадщини через прототипи, вам потрібно покрити відмінності більш докладно! - James
Я думаю, що ця відповідь є трохи помилковою. - Armin Cifuentes


Прочитавши цей потік, я почуваюся заплутаним з мережею прототипів JavaScript, потім знайшов ці діаграми

http://iwiki.readthedocs.org/en/latest/javascript/js_core.html#inheritance *[[protytype]]* and <code>prototype</code> property of function objects

це чітка діаграма, щоб показати спадщину JavaScript за ланцюгом прототипів

і

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

цей приклад містить код та декілька гарних діаграм.

Прототипна ланцюг, зрештою, повертається до об'єкта. Прототип.

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

Сподіваємося, що це також допоможе вам зрозуміти ланцюжок прототипів JavaScript.


59
2018-05-26 20:40



Було б чудово, якщо б ви могли надати короткий абзац змісту посилань, щоб ця відповідь була корисною, коли посилання були мертвими. - Nicktar
@Nicktar, Дякую за вашу пропозицію, я додав просте опис за цими посиланнями. - rockXrock
це чітка графіка? :) - Nuno_147
Діаграма говорить тисячі слів. Це настільки корисно :) - Mark Robson
Ви можете пояснити що [[Prototype]] засоби? - CodyBugstein


Сім коанів прототипу

Коли Чіро Сан з глибинної медитації спустився на гору Фрікс, його розум був ясним і миролюбним.

Його рука, однак, була неспокійною і сама по собі схопила пензлем і записала наступні нотатки.


0) Дві різні речі можна назвати "прототипом":

  • власність прототипу, як в obj.prototype

  • прототип внутрішньої властивості, позначений як [[Prototype]]  в ES5.

    Його можна отримати за допомогою ES5 Object.getPrototypeOf().

    Firefox робить його доступним через __proto__ власність як продовження ES6 згадує зараз деякі додаткові вимоги для __proto__.


1) Ці поняття існують, щоб відповісти на питання:

Коли я роблю obj.property, де шукає JS .property?

Інтуїтивно, класична спадщина повинна впливати на пошук власності.


2)

  • __proto__ використовується для точки . пошук майна як в obj.property.
  • .prototype є ні використовується для пошуку безпосередньо, лише опосередковано, як це визначає __proto__ при створенні об'єкта з new.

Порядок пошуку:

  • obj властивості додані з obj.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() {}
var f = new F()

Відповідає наступній діаграмі:

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

Ця діаграма показує багато мов попередньо визначених вузлів об'єкта: null, Object, Object.prototype, Function і Function.prototype. Наші 2 рядки коду тільки створені f, F і F.prototype.


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.constructor, JavaScript робить . пошук як:

  • f не має .constructor
  • f.__proto__ === F.prototype мав .constructor === F, тому візьміть це

Результат f.constructor == F інтуїтивно правильний, оскільки F використовується для побудови f, наприклад встановлювати поля, як і в класичних мовах OOP.


6) Класичний синтаксис успадкування може бути досягнутий шляхом маніпулювання прототипами ланцюгів.

ES6 додає class і 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.
(new C(1)).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

Спрощена схема без всіх попередньо визначених об'єктів:

      __proto__
(C)<---------------(D)         (d)
| |                |           |
| |                |           |
| |prototype       |prototype  |__proto__
| |                |           |
| |                |           |
| |                | +---------+
| |                | |
| |                | |
| |                v v
|__proto__        (D.prototype)
| |                |
| |                |
| |                |__proto__
| |                |
| |                |
| | +--------------+
| | |
| | |
| v v
| (C.prototype)--->(inc)
|
v
Function.prototype

57
2018-06-18 19:48



Я не знаю, де ви отримали це, але це найяскравіша відповідь! - tomasb
@tomasb спасибі! "Я не знаю, де ви це отримали": після того як я бачив деякі з цих динамічних мов, я помітив, що найбільше важливо про їх класну систему, це те, як . пошукові роботи (і скільки копій даних робиться). Тому я вирішив зрозуміти це. Решта - це публікації в блозі Google + і перекладач Js. :) - Ciro Santilli 新疆改造中心 六四事件 法轮功
Ця відповідь показує справжнє та глибоке розуміння цієї концепції. Хороша робота! - Nir Smadar
Я досі не розумію, чому g.constructor === Об'єкт, тому що ви сказали, що "4) Коли ви робите f = новий F, новий також встановлює f.constructor = F". Не могли б ви пояснити мені більше? У будь-якому випадку це найкраща відповідь, яку я шукаю. Дуже дякую! - nguyenngoc101
@Тепер все зрозуміло, я проголосував за вашу відповідь. Дякую за допомогу. - nguyenngoc101


Кожен об'єкт має внутрішню властивість [[Prototype]], зв'язавши його з іншим об'єктом:

object [[Prototype]] -> anotherObject

У традиційному javascript пов'язаний об'єкт є prototype властивість функції:

object [[Prototype]] -> aFunction.prototype

Деякі середовища піддають [[Prototype]] як __proto__:

anObject.__proto__ === anotherObject

Ви створюєте посилання [[Prototype]] при створенні об'єкта.

// (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;

А. new Заява не показує ціль посилання (Object.prototype) сама; Замість цього ціль має на увазі конструктор (Object)

Пам'ятай:

  • Кожен об'єкт має посилання, [[Prototype]], іноді виставляється як __proto__.
  • Кожна функція має a prototype власність
  • Об'єкти, створені за допомогою new пов'язані з prototype майно їх конструктора.
  • Якщо функція ніколи не використовується як конструктор, її prototype майно буде невикористаним.
  • Якщо вам не потрібен конструктор, скористайтеся Object.create замість new.

33
2018-02-21 12:41



+1 для виділення об'єкта. Create () - Jakob Sternberg
У редакції 5 вилучено деяку корисну інформацію, включно з інформацією про Object.create (). Побачити перегляд 4. - Palec
@Palec, що я повинен додати назад? - sam
ІМО принаймні посилання на Object.create() документи, @sam Посилання на __proto__ і Object.prototype Буде чудовим удосконаленням. І мені сподобалося ваші приклади того, як прототипи працюють з конструкторами і Object.create(), але вони, мабуть, були довгою і менш важливою частиною, яку ви хотіли позбутися. - Palec
з усієї дискусії, що я отримую (прийшла з класичної спадщини), якщо я створюю функцію конструктора і намагаюся створити її екземпляр за допомогою нового оператора, я отримаю лише ті методи та властивості, які було прикріплено до прото-об'єкту, тому його необхідно приєднати до всього методу і властивості для об'єкта proto, якщо ми хочемо успадкувати, будь-ласка, правильно? - blackHawk