Як працює JavaScript .prototype?


2041

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

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

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

Але яка точна мета цього властивості ".prototype" у 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

Також ці слайди справді дуже допомогли.


78
Джон Резіг має кілька слайдів про прототипи функцій, які були мені корисні при вивченні теми (ви також можете внести зміни в код і подивитися, що відбувається ...) http://ejohn.org/apps/learn/#64
Джон Фостер

5
Чудовий довідковий матеріал, щоб зробити це питання інформативним, можливо, розмістіть деякі коментарі з сайту Джона на вашій відповіді, якщо його сайт зміниться таким чином, що ваше посилання більше не доступне. У будь-якому випадку +1, мені допомогли.
Кріс

95
+1 для вашого посилання на слайд JavaScript Ninja № 64 Джона Ресіга . Починати звідти було дуже корисно, і я відчуваю, що я правильно розумію прототипи.
платний ботанік

4
Чи справді нам потрібен функціональний об’єкт для застосування прототипу? якщо так, ніж чому?
Аншул

6
Це може допомогти вам: webdeveasy.com/javascript-prototype
Naor

Відповіді:


1007

Кожен об'єкт JavaScript має внутрішній «слот» під назвою [[Prototype]], значення якого або nullабо object. Ви можете вважати слот як властивість об'єкта, внутрішнього в двигуні JavaScript, прихованого від написаного вами коду. Квадратні дужки навколо [[Prototype]]є навмисними і є умовою специфікації ECMAScript для позначення внутрішніх прорізів.

Значення, на яке вказує [[Prototype]]об'єкт, розмовно називається "прототипом цього об'єкта".

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

Сучасні реалізації JavaScript дозволяють читати та / або записувати доступ до [[Prototype]]таких способів:

  1. В newоператорі (конфигурирует прототип ланцюг на об'єкті за замовчуванням повертається з функції конструктора),
  2. extendsКлючове слово (налаштовує ланцюжок прототипів при використанні синтаксису класу),
  3. Object.createвстановить наданий аргумент як [[Prototype]]об'єкт, що виходить,
  4. Object.getPrototypeOfі Object.setPrototypeOf(отримати / встановити [[Prototype]] після створення об'єкта), і
  5. Стандартизований властивість accessor (тобто 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
Отже, я роблю щось не так, визначаючи нові властивості прототипу властивості у своєму короткому фрагменті?
Джон Лейдегрен

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

8
Я ненавиджу нестандартні речі, особливо в мовах програмування, чому існує навіть протокол, коли він явно не потрібен?
Джон Лейдегрен

1
@John __proto__ потрібен для внутрішнього використання лише перекладачем JS. Кожен Об'єкт повинен знати, які властивості та методи є частиною прототипу, а які - частиною самого Об'єкта. Інтерпретатору 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());

Хоча, як було сказано, я не можу зателефонувати на setAmountDue (), getAmountDue ().

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

352
Я думаю, що відповіді на stackoverflow цікаві не лише оригінальному плакату, але й великій спільноті інших людей, які ховаються або йдуть від пошуків. І я був одним із них, і я мав користь від старих постів. Я думаю, що я міг би сприяти іншим відповідям, додаючи кілька прикладів коду. Щодо вашого питання: якщо ви залишите нове, воно не спрацює. коли я закликаю myCustomer.sayMyName (), він повертає "myCustomer.sayMyName - не функція". Найпростіший спосіб - експериментувати з firebug і подивитися, що відбувається.
stivlo

7
Наскільки я розумію var Person = функція (ім'я) {...}; визначає функцію конструктора, здатного будувати об'єкти людини. Тож ще немає Об'єкта, лише Особиста функція анонімного конструктора призначена Особі. Це дуже вдале пояснення: helephant.com/2008/08/how-javascript-objects-work
stivlo

17
УВАГА: Ця відповідь нехтує тим фактом, що конструктор батьківського класу не викликається на основі екземпляра. Єдина причина, по якій це працює, полягає в тому, що він зробив абсолютно те саме (встановивши ім'я) і в дочірньому, і в батьківському конструкторі. Для більш глибокого пояснення поширених помилок, зроблених при спробі успадкування JavaScript (та остаточного рішення), будь ласка, дивіться: цей пост переповнення стека
Арен Кордова

3
Я зауважую, що ця відповідь також не згадує, що використовуючи "новий Person ()" в якості прототипу, ви фактично встановлюєте властивість екземпляра "name" "Person" статичною властивістю "Замовника" (тому всі Клієнти екземпляри матимуть однакову властивість). Хоча це хороший основний приклад, НЕ РОБИТИ ЦЕ. :) Створіть нову анонімну функцію, щоб вона діяла як "міст", встановивши її прототип на "Person.prototype", потім створіть з неї екземпляр і встановіть замість цього "Customer.prototype" на цей анонімний екземпляр.
Джеймс Вілкінс

10
Щодо Customer.prototype = new Person();рядка, MDN показує приклад використання Customer.prototype = Object.create(Person.prototype)та констатує, що "Поширеною помилкою тут є використання" нової особи () "' . джерело
Рафаель Ейнг

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

Таким чином , в цьому кроці 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. Це означає, що ми мали б, 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об'єкт.

c. У 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); } };

в цій частині я намагаюся зробити всі кроки, які виконує JavaScript, не використовуючи newключове слово, і prototype, коли ви використовуєте 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();

c. тоді він дає цей об'єкт конструктору,

ми можемо зробити це за допомогою нашого зразка, наприклад:

Person.call(newObject, "George");

або

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

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

тепер кінцевий результат перед моделюванням інших кроків: Об'єкт {name: "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.

Прототип ланцюга

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


6
а) Будь ласка , не пояснюють прототипи шляхом копіювання властивостей б) Установка внутрішнього [[Prototype]] відбувається до того , як функція - конструктор застосовується на примірнику, будь ласка , змінити цей порядок с) JQuery повністю оффтоп в цьому питанні
Берги

1
@ Бергі: дякую за вказівку, я буду вдячний, якщо ви дасте мені знати, чи зараз це нормально.
Мехран Хатамі

7
Чи можете ви, будь ласка, зробити це просто? Ви маєте рацію у всіх питаннях, але студенти, які читають це пояснення, можуть вперше заплутатися. візьміть будь-який простіший приклад і дозвольте коду пояснити себе або додати купу коментарів, щоб уточнити, що ви маєте на увазі.
PM

2
@PM: Дякую за відгук. Я намагався зробити це якомога простіше, але, думаю, ви праві, все ж є деякі невиразні моменти. Тому я спробую це змінити, а також бути більш описовим. :)
Мехран Хатамі

1
@AndreaMattioli, оскільки таким чином ви створюєте абсолютно новий об'єкт і переосмислюєте старий, який може бути спільним для інших об’єктів. Замінивши __proto__спочатку, ви стерте всі властивості прототипу верхнього рівня, а потім у вас з'явиться свіжа база прототипів, яка вже не поділяється, якщо ви не поділитесь нею.
Мехран Хатамі

77

Сім Коана прототипу

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

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


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(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__, дужки, обов'язкові для задоволення синтаксису)

Наші 2 рядки коду створили лише такі нові об’єкти:

  • f
  • F
  • F.prototype

iтепер є власністю, fтому що коли ви робите:

var f = new F(1)

він оцінює Fз thisтого значенням , яке 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.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.
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.i до , 1як описано в «4)».

На другому рядку, коли ми робимо:

c.inc()
  • .incвиявляється через [[Prototype]]ланцюг: c->C -> C.prototype->inc
  • коли ми називаємо функцію в Javascript as X.Y(), JavaScript автоматично встановлюється thisрівним XвсерединіY() виклику функції!

Точно та ж логіка також пояснює d.inc і d.inc2.

У цій статті https://javascript.info/class#not-just-a-syntax-sugar згадуються подальші ефекти, які classварто знати. Деякі з них можуть бути недосяжними без цьогоclass ключового слова (перевірити TODO):


1
@tomasb дякую! "Я не знаю, звідки ви це взяли": після того, як я побачив декілька цих динамічних мов, я помітив, що найбільше важливо в їхній системі класів, як .працює пошук (і скільки копій даних зроблено) . Тож я поклав на меті зрозуміти цей момент. Решта - публікації в блогах Google + + перекладач Js. :)
Ciro Santilli 冠状 病毒 审查 六四 事件 法轮功

1
Я все ще не розумію, чому g.constructor === Об'єкт, тому що ви сказали, що "4) Коли ви робите f = new F, новий також встановлює f.constructor = F". Не могли б ви мені пояснити більше? У будь-якому випадку це найкраща відповідь, яку я шукаю. Дуже дякую!
nguyenngoc101

@ nguyenngoc101 дякую! sets f.constructor = FЧастина була явно неправильно і суперечить з іншими розділами: .constructorзнайдений через .пошук на ланцюжку прототипів. Виправлено це зараз.
Ciro Santilli 冠状 病毒 审查 六四 事件 法轮功

з усієї дискусії, що я отримую (прийшов від класичного успадкування), якщо я створю функцію конструктора і спробую створити його екземпляр за допомогою нового оператора, я отримаю лише методи та властивості, які були прикріплені до протооб'єкта, тому необхідно приєднати весь метод та властивості для об'єкта proto, якщо ми хочемо успадкувати, правда?
blackHawk

1
@CiroSantilli 刘晓波 死 六四 事件 法轮功 Я не думаю, що це помилка в Chromium. Я думаю, що це лише симптом, fз якого прототип встановлюється Fлише на час будівництва; fне знатимуть і не піклуватимуться про це F.prototypeв будь-який час після його спорудження.
Джон Глассмер

76

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 став класом, який зараз можна інсталювати. Існує кілька примірників obj, і всі вони маютьtest функцію.

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


13
-1: prototypeвластивість функцій конструктора, а не екземплярів, тобто ваш код неправильний! Можливо, ви мали на увазі нестандартну властивість __proto__предметів, але це зовсім інший звір ...
Крістоф

@Christoph - Дякую, що вказав на це. Я оновив зразок коду.
Рамеш

3
Тут так багато іншого ... Плюс JavaScript не є мовою на основі класу - він має справу з успадкуванням за допомогою прототипів, вам потрібно детальніше висвітлити відмінності!
Джеймс

5
Я вважаю, що ця відповідь трохи помилково.
Армін Сіфуентес

Можливо, відповідь є "хибною", але пояснюється, для чого використовується прототип, і тепер мені все зрозуміло, адже всі "відповіді" мають сотні голосів "вгору". Дякую.
Алекс

66

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

http://iwiki.readthedocs.org/en/latest/javascript/js_core.html#inheritance * [[типізація]] * та <код> прототипу </code> властивість функціональних об'єктів

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

і

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

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

Прототип ланцюга в кінцевому підсумку повертається до Object.prototype.

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

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


Чи можливо мати багатократне успадкування на Javascript?

Чи тут Foo об'єкт буквальний чи функціональний об'єкт? Якщо його об'єкт буквальний, я вважаю, що Foo.prototype не буде вказувати на Foo через конструктор.
Мадхур Ахуджа

@ user3376708 JavaScript підтримує лише одне спадкування ( джерело )
Рафаель Ейн

@ Nuno_147 Спочатку це незрозуміло, але якщо ви будете виглядати досить довго, ви можете отримати щось із цього.
marcelocra

3
Чи можете ви пояснити, що [[Prototype]]означає?
CodyBugstein

40

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

object [[Prototype]]  anotherObject

У традиційному javascript пов'язаний об'єкт є 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 ).

Пам'ятайте:

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

1
У версії 5 видалено корисну інформацію, включаючи інформацію про Object.create (). Дивіться редакцію 4 .
Палець

@Palec, що мені додати назад?
сам

2
IMO принаймні посилання на Object.create()документи , @sam. Посилання на __proto__та Object.prototypeбули б приємні покращення. І мені сподобалися ваші приклади того, як прототипи працюють з конструкторами Object.create(), але вони, мабуть, були довгою і менш актуальною частиною, від якої ви хотіли позбутися.
Палець

з усієї дискусії, що я отримую (прийшов від класичного успадкування), якщо я створять конструкторську функцію і спробую створити її примірник за допомогою нового оператора, я отримаю лише методи та властивості, які були приєднані до протооб'єкта, тому необхідно приєднати весь метод та властивості для об'єкта proto, якщо ми хочемо успадкувати, правда?
blackHawk

29

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

прототип ланцюга

Якщо члена об’єкта неможливо знайти в об'єкті, він шукає його в ланцюзі прототипу. Ланцюг складається з інших предметів. Прототип даного примірника може бути доступний за допомогою__proto__ змінної. Кожен об'єкт має його, оскільки різниці між класами та екземплярами у JavaScript немає.

Перевага додавання функції / змінної до прототипу полягає в тому, що вона повинна бути в пам'яті лише один раз, а не для кожного примірника.

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


1
FF і Chrome підтримують прото , але не IE, ні Opera.
десь

Георг, уточнюйте, будь ласка, для noob - "між класами та екземплярами у javascript немає різниці". - Ви могли б детальніше розробити? Як це працює?
Хаміш Грубіян

з усієї дискусії, що я отримую (прийшов від класичного успадкування), якщо я створять конструкторську функцію і спробую створити її примірник за допомогою нового оператора, я отримаю лише методи та властивості, які були приєднані до протооб'єкта, тому необхідно приєднати весь метод та властивості для об'єкта proto, якщо ми хочемо успадкувати, правда?
blackHawk

28

Ця стаття довга. Але я впевнений, що це очистить більшість ваших запитів щодо "прототипічного" характеру наслідування JavaScript. І навіть більше. Прочитайте повну статтю.

В основному JavaScript має два типи даних

  • Не об’єкти
  • Об'єкти

Не об’єкти

Далі наводяться типи даних без об’єктів

  • рядок
  • кількість (включаючи NaN та нескінченність)
  • булеві значення (вірні, хибні)
  • невизначений

Ці типи даних повертаються після використання оператора typeof

typeof "string literal" (або змінна, що містить string literal) === 'string'

typeof 5 (або будь-який числовий літерал або змінна, що містить числовий літерал або NaN або Infinnity ) === 'число'

typeof true (або false або змінна, що містить true або false ) === 'boolean'

typeof undefined (або невизначена змінна або змінна, що містить undefined ) === 'undefined'

Рядок , число і булеві типи даних можуть бути представлені як в вигляді об'єктів і без об'єктів .Коли вони представлені як об'єкти їх TypeOf завжди === «об'єкт». Ми повернемося до цього, як тільки зрозуміємо типи даних об’єктів.

Об'єкти

Типи даних об'єктів можна далі розділити на два типи

  1. Об'єкти типу функцій
  2. Об'єкти нефункціонального типу

Ці об'єкти типу Function є ті , які повертають рядок «функцію» з TYPEOF оператором. Усі визначені користувачем функції та всі вбудовані JavaScript в об’єкти, які можуть створювати нові об’єкти за допомогою нового оператора, підпадають під цю категорію. Наприклад, наприклад.

  • Об'єкт
  • Рядок
  • Номер
  • Булева
  • Масив
  • Набрані масиви
  • RegExp
  • Функція
  • Усі інші вбудовані об'єкти, які можуть створювати нові об'єкти за допомогою нового оператора
  • функція UserDefinedFunction () {/ * визначений користувачем код * /}

Отже, typeof (Object) === typeof (String) === typeof (Кількість) === typeof (Булева) === typeof (Масив) === typeof (RegExp) === typeof (Функція) == = typeof (UserDefinedFunction) === 'функція'

Усі об'єкти типу Функція - це фактично вбудовані в об’єкт JavaScript функції Function (включаючи об'єкт 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")

Як уже згадувалося, об'єкти типу Функція можуть додатково створювати нові об'єкти за допомогою нового оператора . Наприклад, наприклад, об’єкт типу 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() 

Таким чином, створені об'єкти - це всі об'єкти нефункціонального типу та повертають їх typeof === 'об'єкт' . У всіх цих випадках об'єкт "a" не може далі створювати об'єкти за допомогою оператора new. Отже, таке неправильне

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

Вбудований об'єкт Math є typeof === 'object' . Отже, новий об’єкт типу Math не може бути створений новим оператором.

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

Також зауважте, що функції Object , Array та RegExp можуть створювати новий об'єкт, навіть не використовуючи новий оператор . Однак наступних - ні.

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}

Ця властивість "прототипу" присутня лише в об'єктах типу "Функція" (і ніколи в об'єктах типу "Нефункція" ).

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

Ця "внутрішня посилання" , створена в об'єкті для посилання на успадковані властивості, відома як прототип об'єкта (який посилається на об'єкт, на який посилається властивість "прототипу" Конструктора, але відрізняється від нього). Для будь-якого об'єкта (функція або нефункція ) це можна отримати за допомогою методу Object.getPrototypeOf () . За допомогою цього методу можна простежити прототип ланцюга об'єкта.

Також кожен створений об'єкт ( Тип функції або тип нефункції ) має властивість "конструктор", яка успадковується від об'єкта, на який посилається властивість прототипу функції Конструктора. За замовчуванням це властивість "конструктор" посилається на функцію Constructor, яка його створила (якщо "прототип" за замовчуванням функції "Конструктора " не змінено).

Для всіх об'єктів типу Функція функцією конструктора завжди є функція Function () {}

Для об'єктів типу "Нефункція" (наприклад, Javascript Built in Math object) функція конструктора - це функція, яка її створила. Для об'єкта Math це функція Object () {} .

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

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.prototype -> Object.prototype -> null
  • Прості об'єкти (створені новим Object () або {}, включаючи вбудований об'єкт Math) -> Object.prototype -> null
  • Об'єкт створений за допомогою нового або Object.create -> Один або декількох ланцюгів прототипу -> Object.prototype -> null

Для створення об'єкта без прототипу використовуйте наступне:

var o=Object.create(null)
alert(Object.getPrototypeOf(o)) //Displays 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

Далі у підсумку цієї статті

  • Існує два типи об'єктів: типи функцій та типи, що не функціонують
  • Тільки об'єкти типу функції можуть створити новий об'єкт за допомогою оператора new . Об'єкти, створені таким чином, є об'єктами нефункціонального типу . Об'єкти типу " Нефункція " не можуть додатково створити об'єкт за допомогою оператора new .

  • Усі об'єкти типу функцій за замовчуванням мають властивість "прототип" . Це "прототип" властивості посилається на об'єкт, який має властивість "конструктор", який за замовчуванням посилається на сам об'єкт типу Функція .

  • Усі об'єкти ( Тип функції та Нефункціональний тип ) мають властивість "конструктор", яке за замовчуванням посилається на об'єкт типу Функція / Конструктор, який його створив.

  • Кожен створений об'єкт внутрішньо посилається на об'єкт, на який посилається властивість "прототипу" Конструктора, який його створив. Цей об'єкт відомий як прототип створеного об'єкта (який відрізняється від властивості типу "функція" "прототип", на яку він посилається). Таким чином створений об'єкт може безпосередньо отримувати доступ до методів і властивостей, визначених в об'єкті, на який посилається властивість "прототипу" Конструктора (на момент створення об'єкта).

  • An прототип об'єкта (і , отже , його спадкові імена властивостей) можуть бути отримані з допомогою Object.getPrototypeOf () метод. Фактично цей метод може бути використаний для навігації по всьому прототипу ланцюга об'єкта.

  • Лабораторія прототипу кожного об'єкта в кінцевому рахунку простежується до Object.prototype (якщо об'єкт не створений за допомогою Object.create (null); у цьому випадку об'єкт не має прототипу).

  • typeof (новий масив ()) === 'об’єкт' - це дизайн мови, а не помилка, як вказував Дуглас Крокфорд

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

Сподіваюсь, це допомагає.


24

Поняття prototypalуспадкування є одним із найскладніших для багатьох розробників. Спробуємо розібратися в корені проблеми, щоб prototypal inheritanceкраще зрозуміти . Почнемо з plainфункції.

введіть тут опис зображення

Якщо ми використовуємо newоператор на Tree function, ми називаємо це constructorфункцією.

введіть тут опис зображення

Кожна JavaScriptфункція має a prototype. Коли ви входите в систему Tree.prototype, ви отримуєте ...

введіть тут опис зображення

Якщо ви подивитеся на вищенаведений console.log()вихід, ви могли б побачити властивість конструктора на Tree.prototypeі також __proto__властивість. __proto__Представляє , prototypeщо це functionбазується, і так як це просто звичайний JavaScript functionз не inheritanceвстановити ще, це відноситься до Object prototypeщо - то просто вбудовується в JavaScript ...

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

Це такі речі, як .toString, .toValue, .hasOwnPropertyі т.д. ...

__proto__який приніс мою мозілу, застарілий і замінений Object.getPrototypeOfметодом отримання object's prototype.

введіть тут опис зображення

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

Додамо метод до нашого Tree prototype.

введіть тут опис зображення

Ми змінили Rootта додали functionдо нього гілку.

введіть тут опис зображення

Це означає , коли ви створюєте instanceз Tree, ви можете назвати це branchметод.

введіть тут опис зображення

Ми також можемо додати primitivesабо objectsдо наших Prototype.

введіть тут опис зображення

Додамо child-treeдо нашого Tree.

введіть тут опис зображення

Тут Childуспадковується його prototypeвід Дерева, те, що ми тут робимо, - це Object.create()метод, щоб створити новий об'єкт на основі того, що ви передаєте, ось він Tree.prototype. У цьому випадку ми робимо встановлення прототипу Child на новий об'єкт, який виглядає ідентично Treeпрототипу. Далі ми встановлюємо Child's constructor to Child, якщо ми цього не вказували б Tree().

введіть тут опис зображення

Childтепер є свої prototype, свої __proto__пункти Treeі Tree's prototypeбази на базі Object.

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

Тепер ви створюєте instanceз Childі виклику , branchякий спочатку доступний в Tree. Ми насправді не визначили нашу branchна Child prototype. АЛЕ, в Root prototypeякому дитина успадковує.

введіть тут опис зображення

У JS все не є об'єктом, усе може діяти як об’єкт.

Javascriptмає примітиви , як strings, number, booleans, undefined, null.вони не є object(i.e reference types), але , звичайно , може діяти як object. Розглянемо приклад тут.

введіть тут опис зображення

У першому рядку цього списку primitiveімені присвоюється рядок. Другий рядок трактує ім'я як objectі називає charAt(0)точкову нотацію.

Ось що відбувається за лаштунками: // що JavaScriptробить двигун

введіть тут опис зображення

String objectІснує тільки одна заява , перш ніж він буде знищений (цей процес називається autoboxing). Давайте знову повернемося до наших prototypal inheritance.

  • Javascriptпідтримує спадкування через delegationзаснований на prototypes.
  • У кожного Functionє prototypeвластивість, яка посилається на інший об’єкт.
  • properties/functionsдивляться з objectсебе або через prototypeланцюг, якщо його немає

A prototypeв JS - це об'єкт, який 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__посилання на яку є прототипом Функції constructor.

введіть тут опис зображення

Наведена вище схема виглядає трохи складно, але виводить всю картину щодо того, як prototype chaining працює. Давайте пройдемося по цьому повільно:

Є два примірника b1і b2, конструктор якого є Barі батько Foo і має два методи з ланцюга прототипів identifyі speakчерез BarіFoo

введіть тут опис зображення

https://jsfiddle.net/kbp7jr7n/

Якщо ви шукаєте код вище, у нас є Fooконструктор, який має метод, identify()і Barконструктор, який має speakметод. Ми створюємо два Barпримірника b1і b2чий батьківський тип Foo. Тепер, використовуючи speakметод виклику Bar, ми можемо визначити того, хто викликає розмову по prototypeланцюгу.

введіть тут опис зображення

Barтепер є всі методи, Fooякі визначені в його prototype. Давайте копати далі в розумінні Object.prototypeі Function.prototypeі як вони пов'язані між собою . Якщо ви подивіться на конструктор Foo, Barі Objectє Function constructor.

введіть тут опис зображення

prototypeЗ Barце Foo, prototypeз FooIS Objectі якщо ви подивіться тісно prototypeвід Fooпов'язано Object.prototype.

введіть тут опис зображення

Перш ніж ми закриємо це, давайте просто обернемо тут невеликий шматочок коду, щоб підсумувати все вище . Ми тут використовуємо instanceofоператор, щоб перевірити, чи objectмає у своєму prototypeланцюжку prototypeвластивість a, constructorяка нижче, підсумовує всю велику діаграму.

введіть тут опис зображення

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


22

яка точна мета цього властивості ".prototype"?

Інтерфейс до стандартних класів стає розширюваним. Наприклад, ви використовуєте Arrayклас і вам також потрібно додати спеціальний серіалізатор для всіх об’єктів масиву. Чи витрачаєте ви час на кодування підкласу, або використовуєте склад або ... Властивість прототипу вирішує це, дозволяючи користувачам контролювати точний набір членів / методів, доступних для класу.

Подумайте про прототипи як додатковий vtable-pointer. Коли деякі учасники відсутні у вихідному класі, прототип шукають під час виконання.


21

Це може допомогти класифікувати прототипові ланцюги на дві категорії.

Розглянемо конструктор:

 function Person() {}

Значення Object.getPrototypeOf(Person)- це функція. Насправді так і є Function.prototype. Оскільки він Personбув створений як функція, він поділяє той самий об’єкт функції прототипу, що і всі функції. Це те саме Person.__proto__, що і не можна використовувати. У будь-якому випадку, Object.getPrototypeOf(Person)ви ефективно піднімаєтесь по сходах того, що називається прототипом ланцюга.

Ланцюг у напрямку вгору виглядає приблизно так:

    PersonFunction.prototypeObject.prototype(кінцева точка)

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

Візьмемо для прикладу цей об’єкт:

var p = new Person();

p не має прямих взаємозв'язків прототипу-ланцюга з Person . Їхні стосунки різні. Об'єкт 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 на один крок довший, ніж р :

    tpPerson.prototypeObject.prototype(кінцева точка)

Інший ланцюг прототипу вже не є: Thiefі Personбрати, які діляться тим самим батьків у своєму прототипі:

    Person}
    Thief  } → Function.prototypeObject.prototype(кінцева точка)

Попередньо представлена ​​графіка може бути розширена до цього (оригінал Thief.prototypeзалишається осторонь):

введіть тут опис зображення

Сині лінії представляють прототипи ланцюгів, інші кольорові лінії представляють інші відносини:

  • між об'єктом та його конструктором
  • між конструктором і об'єктом-прототипом, який буде використовуватися для побудови об'єктів

18

Остаточний посібник по об’єктно-орієнтованому JavaScript - дуже стисле і чітке пояснення на 30-хвилинне відео (30-хвилинне відеозапитання). Тема "Прототипне успадкування" починається з 5:45 , хоча я хотів би прослухати все відео). Автор цього відео також зробив веб-сайт візуалізаторів об’єктів JavaScript http://www.objectplayground.com/ .введіть тут опис зображення введіть тут опис зображення


1
відмінна відеопосилання
lukeaus

16

Мені було корисно пояснити "прототип ланцюга" як рекурсивну умову, коли obj_n.prop_Xна нього посилаються:

якщо obj_n.prop_Xйого немає, перевірте, obj_n+1.prop_Xдеobj_n+1 = obj_n.[[prototype]]

Якщо prop_Xостаточно знайдено в k-му об'єкті-прототипі, тоді

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

Ви можете знайти графік відношення об'єктів Javascript за їх властивостями тут:

Графік об'єктів js

http://jsobjects.org


14

Коли конструктор створює об'єкт, цей об'єкт неявно посилається на властивість "прототипу" конструктора з метою вирішення посилань на властивості. Властивість "прототипу" конструктора може посилатися на програмний вираз 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.prototype, в .prototype«S [[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(). Object.create(model)створює новий об'єкт і встановлює його [[прототип]] властивість до об'єктної моделі . Отже, коли ви це зробите Object.getPrototypeOf(product), ви отримаєте об'єктну модель .

Властивості продукту обробляються таким чином:

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

Таке пов'язування об’єктів за допомогою властивості прототипу називається прототиповим успадкуванням. Там так просто, погодьтеся?


Не завжди написано на продукт при дорученні. Ви не даєте зрозуміти, що певні екземпляри повинні бути ініціалізовані, а спільні члени можуть перейти на прототип. Особливо, якщо у вас є певні примірники, що змінюються, наприклад: stackoverflow.com/questions/16063394/…
HMR

HMR: У вашому прикладі у вашій відповіді ben.food.push ("Гамбургер"); рядок змінює властивість об'єкта-прототипу завдяки наступному: 1.) Спочатку ben.food переглядається, і будь-яка дія пошуку просто знайде ланцюг області. 2.) Функція push цього об'єкта ben.food виконується. Під режимом написання у своїй відповіді я маю на увазі, коли ви явно встановлюєте для нього значення, як у: ben.food = ['Idly']; Це завжди створить нове властивість (якщо його вже немає) на об’єкті продукту, а потім призначить йому значення.
Aravind

HMR: Дякую за ваш коментар, це змусило задуматися і перевірити своє розуміння.
Аравінд

При повторному призначенні ben.food він затінить член їжі, якщо їжа не створена за допомогою Object.defineProperty, Object.defineProperties або Object.create з другим аргументом (так не завжди). Ви навіть можете змінити прототип за допомогою (як виглядає) повторного призначення, коли ви створили геттер. Що стосується шаблонів успадкування, я розумію, що конструкторську функцію важко зрозуміти і має деякі основні проблеми, але добре, якщо ви її розумієте. Спадкування в 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

Тепер, припустимо, ми створимо 100 примірників цього keyValueStoreоб’єкта. Незважаючи на те get, set, delete,getLength буде робити ту ж саму річ для кожного з цих 100 примірників, кожен екземпляр має свою власну копію цієї функції.

Тепер уявіть, що якби ви могли мати тільки один get, set, deleteіgetLength копію, і кожен екземпляр буде посилатися на ту ж саму функцію. Це було б краще для продуктивності та вимагало б менше пам’яті.

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

Тепер 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

Підсумок:

  • Функції - це об'єкти в JavaScript і, таким чином, можуть мати властивості
  • (Конструктор) функції завжди мають властивість прототипу
  • Коли функція використовується як конструктор з 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 є механізм при пошуку властивостей на об'єктах, який називається "прототипне успадкування" , ось що в основному робить:

  • Спочатку перевіряється, чи властивість знаходиться на самому Об'єкті. Якщо так, це властивість буде повернуто.
  • Якщо властивість не знаходиться на самому об’єкті, воно буде "підніматися в протокол". Він в основному розглядає об'єкт, на який посилається властивість 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 справді є запасна ручка і передає її Фініусу, який передає її вам, щоб виконати свою вікторину. Дерп довірив ручку Фініусу, який делегував ручку вам для використання.

Тут важливо те, що Дерп не дає вам ручки, так як ви не маєте з ним прямого зв'язку .

Це - спрощений приклад того, як працюють прототипи, де дерево даних шукає те, що ви шукаєте.


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

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

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