__proto__ В.С. прототип в JavaScript


785

Цей малюнок ще раз показує, що кожен об’єкт має прототип. Функція конструктора Foo також має свою __proto__функцію, яка є Function.prototype, і яка, у свою чергу, також посилається через свою __proto__властивість знову на Object.prototype. Таким чином, повторимо, Foo.prototype - це явне властивість Foo, яке стосується прототипу об'єктів b і c.

var b = new Foo(20);
var c = new Foo(30);

Які відмінності між __proto__і prototype?

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

Фігура взята з dmitrysoshnikov.com .



5
Я вважаю, що це питання переваги зверху вниз чи знизу вгору. Я насправді віддаю перевагу саме цьому, тому можу простежити діаграму, поки не знайду, звідки щось походить.
Майк Ліпперт

1
Мені подобається, як JavaScript використовує прототипне успадкування для вирішення y.constructor до y .__ proto __. Конструктора. Мені також подобається, як Object.prototype сидить у верхній частині прототипічного ланцюжка успадкування, а Object.prototype .__ proto__ встановлений на нуль. Мені також подобається, як діаграма робить концептуальну візуалізацію три стовпця про те, як програміст вважає об'єкти як 1. екземпляри, 2. конструктори, 3. прототипи, які конструктори асоціюють із тими випадками, коли інстанціюються за допомогою нового ключового слова.
Джон Сондерсон

Діаграма має негайний сенс після того, як ви переглядаєте щось на кшталт youtube.com/watch?v=_JJgSbuj5VI , btw
mlvljr

І тепер, коли я прочитав відповіді, відчувати себе зобов'язаними дійсно рекомендувати вищезазначене відео, як це дійсно має кристально чистий (і не WTFy) пояснення того , що відбувається :)
mlvljr

Відповіді:


765

__proto__- це фактичний об'єкт, який використовується у ланцюзі пошуку для вирішення методів тощо prototype. Об'єкт, який використовується для створення __proto__при створенні об'єкта за допомогою new:

( new Foo ).__proto__ === Foo.prototype;
( new Foo ).prototype === undefined;

239
Ах! Отже, prototypeдоступно не для самих екземплярів (або інших об'єктів), а лише для функцій конструктора.
rvighne

43
@rvighne: prototypeдоступний тільки на функціях , так як вони отримані з Function, Functionі , Objectале ні в чому іншому це не так . Однак __proto__доступний скрізь.
Тарік

19
Тож __proto__власне об'єкт, який зберігається та використовується як прототип, тоді Myconstructure.prototypeяк лише креслення, для __proto__якого фактично об'єкт зберігається та використовується як прототип. Отже, не myobject.prototypeбуде властивістю фактичного об'єкта, оскільки його просто тимчасова річ, яка використовується конструкторською функцією для окреслення того, як myobject.__proto__має виглядати.
Alex_Nabu

9
Чи справедливо сказати, що __proto__властивість об'єкта є вказівником на prototypeвластивість функції конструктора об'єкта? тобто foo .__ proto__ === foo.constructor.prototype
Niko Bellic

10
@Alex_Nabu Не зовсім. newCar.__proto__ Є Car.prototype , а не примірник Car.prototype. Хоча Car.protoype IS є екземпляром object. Car.prototypeце не те , що дає newCarякісь - або властивості або структуру, він просто IS наступного objectВ меню newCar«сек прототип ланцюга. Car.prototypeне є тимчасовим object. Це те, objectщо встановлюється як значення __proto__властивості будь-якого нового objects, зробленого з використанням Carяк constructor. Якщо ви хочете придумати що-небудь як креслення object, подумайте Carяк про креслення для нових автомобілів object.
seangwright

335

prototypeє властивістю об'єкта Функції. Це прототип об'єктів, побудованих за допомогою цієї функції.

__proto__є внутрішньою властивістю об'єкта, що вказує на його прототип. Чинні стандарти пропонують еквівалентний Object.getPrototypeOf(O)метод, хоча стандарт де-факто __proto__швидший.

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

function Point(x, y) {
    this.x = x;
    this.y = y;
}

var myPoint = new Point();

// the following are all true
myPoint.__proto__ == Point.prototype
myPoint.__proto__.__proto__ == Object.prototype
myPoint instanceof Point;
myPoint instanceof Object;

Ось Pointфункція конструктора, вона будує об’єкт (структуру даних) процедурно. myPoint- об'єкт, побудований Point()таким чином, в цей час Point.prototypeзберігається myPoint.__proto__.


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

myPoint .__ прото __. конструктор.прототип == Point.prototype
Франциско

@kzh lol, який дав мені кумедний результат console.log(obj1.call) // [Function: call] obj1.call()// TypeError: obj1.call - це не функція. Я зробивobj.__proto__ = Function.__proto__
abhisekp

myFn.__proto__ = {foo: 'bar'}
кж

Я думаю, що я знайшов вашу точку.
ComicScrip

120

Властивість прототипу створюється при оголошенні функції.

Наприклад:

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

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

// adds a new method age to the Person.prototype Object.
Person.prototype.age = function(){return date-dob}; 

Варто зазначити, що Person.prototypeце Objectза замовчуванням буквальний (його можна змінити у міру необхідності).

Кожен екземпляр, створений за допомогою, new Person()має __proto__властивість, яка вказує на Person.prototype. Це ланцюг, який використовується для переходу для пошуку властивості конкретного об'єкта.

var person1 = new Person(somedate);
var person2 = new Person(somedate);

створює 2 екземпляри Person , ці 2 об'єкти можна назвати ageметод , Person.prototypeяк person1.age, person2.age.

На наведеному вище малюнку із запитання ви бачите, що Fooце є, Function Objectа тому воно має __proto__посилання на те, Function.prototypeщо в свою чергу є екземпляром Objectі має __proto__посилання наObject.prototype . Протопосилання закінчується __proto__на Object.prototypeвказівці на null.

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

__proto__не є стандартним способом доступу до прототипу ланцюга, стандартним, але подібним підходом є використання Object.getPrototypeOf(obj).

Нижче код для instanceof оператора дає краще розуміння:

instanceofОператор класу об'єктів повертається, trueколи об'єкт є екземпляром Класу, точніше, якщо Class.prototypeвін знайдений у прото-ланцюзі цього об'єкта, то об'єкт є екземпляром цього Класу.

function instanceOf(Func){
  var obj = this;
  while(obj !== null){
    if(Object.getPrototypeOf(obj) === Func.prototype)
      return true;
    obj = Object.getPrototypeOf(obj);
  }
  return false;
}      

Вищеописаний метод можна назвати так: instanceOf.call(object, Class)який повертає true, якщо об'єкт є екземпляром Class.


2
Мені було цікаво, чому prototypeв першу чергу створений предмет всередині? Чи можна просто призначити статичний метод самому об’єкту функції. наприклад function f(a){this.a = a}; f.increment = function(){return ++this.a}? Чому не було обрано такий спосіб додавання методів до prototypeоб’єкта? Це буде працювати, якщо f.__proto__ = gg - базовий клас.
abhisekp

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

1
Власне, це було б безладом, оскільки instanceofце призвело б до того ({}) instanceof Function === true, що не було б способу розмежувати прототипи, якщо prototypeвластивість буде вилучена.
abhisekp

@abhisekp Що ви маєте на увазі під цим: "Це буде працювати, якщо f .__ proto__ = g, де g - базовий клас." Я не знаю, чи має це якийсь сенс, який я не розумію, але якби ви додавали властивості та методи таким чином, тоді, коли ви використовували newключове слово для створення примірника, властивості та методи не копіювалися б над.
подвійнийокт

66

Гарний спосіб подумати про це ...

prototypeвикористовується constructor()функціями. Це справді мало би називатися чимось на кшталт "prototypeToInstall", адже саме так воно і є.

і __proto__це "встановлений прототип" на об'єкті (який був створений / встановлений на об'єкті із зазначеної constructor()функції)


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

2
Будь ласка, змініть " constructor()функції" на "функції конструктора", оскільки може виникнути плутанина з " __proto__.constructor()функціями". Я вважаю це важливим, оскільки конструктор __proto __. Фактично не викликається, коли використовується newключове слово.
Олександр Гончій

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

62

Для пояснення створимо функцію

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

Коли JavaScript виконує цей код, він додає prototypeвластивість a, prototypeвластивість - це об'єкт з двома властивостями до нього:

  1. constructor
  2. __proto__

Так коли ми робимо

a.prototype вона повертається

     constructor: a  // function definition
    __proto__: Object

Тепер, як ви бачите, constructorце не що інше, як aсама функція і __proto__вказує на кореневий рівень ObjectJavaScript.

Давайте подивимося, що відбувається, коли ми використовуємо aфункцію з newключовим словом.

var b = new a ('JavaScript');

Коли JavaScript виконує цей код, він робить 4 речі:

  1. Він створює новий об’єкт, порожній об’єкт // {}
  2. Він створює __proto__на bі робить це вказує на a.prototypeSob.__proto__ === a.prototype
  3. Він виконує a.prototype.constructor(що є визначенням функції a) з новоствореним об'єктом (створеним на кроці # 1) як його контекст (це), отже, nameвластивість, передана як "JavaScript" (яка додається до this), додається до новоствореного об'єкта.
  4. Він повертає новостворений об'єкт у (створений на кроці №1), тому var bприсвоюється новоствореному об'єкту.

Тепер якщо ми додамо a.prototype.car = "BMW"і зробимо b.car, з'явиться вихід "BMW".

це тому, що коли JavaScript виконував цей код, він шукав carвластивість b, він не знаходив тоді використовуваний JavaScript b.__proto__(що було зроблено для вказівки на "a.prototype" на кроці №2) і знаходить carвластивість, щоб повернути "BMW".


2
1. constructorне повертається a()! Це повертається a. 2. __proto__повертає Object.prototype, а не кореневий об’єкт у Javascript.
подвійнийокт

1
Це чудова відповідь!
Джон-Раймон

+1 це найкраща відповідь для пояснення того, що насправді прототип IS (об’єкт з двома властивостями) та як Javascript виконує кожен фрагмент коду. Ця інформація напрочуд складна.
java-addict301

53

Прототип В.С. __proto__ В.С. [[Прототип]]

Під час створення функції об'єкт властивості під назвою прототип створюється автоматично (ви його не створили самостійно) і додається до об'єкта функції (the constructor).
Примітка . Цей новий об'єкт- прототип також вказує на або має внутрішньо-приватне посилання на нативний об’єкт JavaScript.

Приклад:

function Foo () {
    this.name = 'John Doe';
}

// Foo has an object property called prototype.
// prototype was created automatically when we declared the function Foo.
Foo.hasOwnProperty('prototype'); // true

// Now, we can assign properties and methods to it:
Foo.prototype.myName = function () {
    return 'My name is ' + this.name;
}

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

var b = new Foo();

b.[[Prototype]] === Foo.prototype  // true


Приватна зв'язок з об'єктом цієї функції назвала подвійні дужки прототипу або просто [[Prototype]]. Багато браузерів надають нам загальнодоступні посилання на те, що називається __proto__!

Якщо бути більш конкретним, __proto__насправді це функція getter, яка належить до рідного JavaScript Object. Вона повертає внутрішній приватно-прототип ув'язку Як би там не thisзв'язування (повертає [[Prototype]]з b):

b.__proto__ === Foo.prototype // true

Варто зазначити, що для початку ECMAScript5, ви також можете використовувати метод getPrototypeOf для отримання внутрішнього приватного зв’язку:

Object.getPrototypeOf(b) === b.__proto__ // true


Примітка: ця відповідь не має наміру охопити весь процес створення нових об'єктів або нові конструкторів, але , щоб краще зрозуміти , що таке __proto__, prototypeі [[Prototype]]та як вона працює.


2
@Taurus, натисніть на заголовок, це призводить до специфікації ECMAScript. Перегляньте розділ 9 (Поведінки звичайних та екзотичних предметів), де це пояснюється набагато детальніше.
Ліор Елром

Я думаю, тут є якась помилка: _ новий об’єкт, який має внутрішнє або приватне посилання на прототип функції Foo_ Ви маєте на увазі: новий об'єкт, який має внутрішнє або приватне посилання на прототип функції Foo ?
Корай Тугай

1
Дякую @KorayTugay! Так, я неправильно написав :) +1
Ліор Елром

30

Щоб зробити це трохи зрозумілим на додаток до вищезазначених чудових відповідей:

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

var eve = new Person("Eve");

eve.__proto__ == Person.prototype //true

eve.prototype  //undefined

Примірники мають __proto__ , класи мають прототип .


12

У JavaScript функція може бути використана як конструктор. Це означає, що ми можемо створювати з них об’єкти за допомогою нового ключового слова. Кожна конструкторська функція має вбудований об'єкт, прикований до них. Цей вбудований об'єкт називається прототипом.Instances of a constructor function use __proto__ to access the prototype property of its constructor function.

діаграма прототипу

  1. Спочатку ми створили конструктор: function Foo(){}. Щоб було зрозуміло, Foo - це лише інша функція. Але ми можемо створити з нього об’єкт за допомогою нового ключового слова. Тому ми називаємо це функцією конструктора

  2. Кожна функція має унікальну властивість, яку називають властивістю прототипу. Отже, функція Constructor Fooмає властивість прототипу, яка вказує на її прототип, який є Foo.prototype(див. Зображення).

  3. Функції конструктора самі по собі є функцією, яка є екземпляром конструктора системи, який називається конструктором [[Функція]]. Тож ми можемо це сказатиfunction Foo побудований конструктором [[Функція]]. Отже, __proto__з нашого Foo functionвкажемо на прототип його конструктора, який є Function.prototype.

  4. Function.prototypeСам по собі є не що інше, як об'єкт, побудований з іншого конструктора системи, який називається [[Object]]. Отже, [[Object]]є конструктором Function.prototype. Отже, можна сказатиFunction.prototype , це примірник [[Object]]. Тож __proto__з Function.prototypeпунктів до Object.prototype.

  5. Object.prototypeє останньою людиною, що стоїть у ланцюзі прототипу. Я маю на увазі, що вона не побудована. Це вже є в системі. Тож його __proto__вказівки на null.

  6. Тепер ми приходимо до примірників Foo. Коли ми створюємо екземпляр за допомогою new Foo(), він створює новий об'єкт, який є екземпляром Foo. Це означає, що Fooє конструктором цих примірників. Тут ми створили два екземпляри (x і y). __proto__x і y таким чином вказує на Foo.prototype.


Щоб було зрозуміло: екземпляри не мають властивості .prototype? Тільки конструктор функціонує правильно? ... Отже, різниця між екземпляром та його конструкторською функцією полягає в тому, що: функції конструктора мають як об'єкт 1. proto 2. .prototype, тоді як екземпляри мають лише властивість .__ proto__ ... правильно?
Shaz

@Shaz ви праві. екземпляри використовують прототипи для доступу до властивості прототипу функції конструктора.
AL-zami

Але чому це так, коли ви пишете: var car = Object.create (Транспортний засіб); ви отримаєте автомобіль .__ proto__ = Транспортний засіб, Але ви також отримаєте властивість car.prototype, яка вказує на Vehicle.prototype?
Shaz

@shaz чи можете ви надати jsfiddle, щоб я міг уявити ситуацію?
AL-zami

1
тут car.prototype - спадкова властивість. автомобіль успадковує властивість "прототипу" від функції транспортного засобу. так car.prototype === транспортний засіб.прототип. Властивість "прототипу" - це властивість на транспортному засобі. автомобіль може отримати доступ до нього через свою прототипу. Сподіваюсь, це очистить вашу плутанину
AL-zami

8

Підсумок:

__proto__Властивість об'єкта є властивістю , яке відображає наprototype функції конструктора об'єкта. Іншими словами:

instance.__proto__ === constructor.prototype // true

Це використовується для формування prototype ланцюга предмета. prototypeЛанцюг є механізм пошуку властивостей на об'єкті. Якщо доступ до властивості об'єкта доступний, JavaScript спочатку подивиться на сам об’єкт. Якщо об’єкт не знайдений там, він підніметься аж до protochainтих пір, поки його не знайдуть (чи ні)

Приклад:

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

Person.prototype.age = 25;

const willem = new Person('Willem');

console.log(willem.__proto__ === Person.prototype); // the __proto__ property on the instance refers to the prototype of the constructor

console.log(willem.age); // 25 doesn't find it at willem object but is present at prototype
console.log(willem.__proto__.age); // now we are directly accessing the prototype of the Person function 

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

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

Чому це корисно?

JavaScript має механізм, коли шукає властивості, за Objectsякими називається "прототипічне успадкування" , ось що в основному це робить:

  • По-перше, це перевіряється, чи властивість знаходиться на самому Об'єкті. Якщо так, це властивість повертається.
  • Якщо властивість не знаходиться на самому об'єкті, воно буде "підніматися в протокол". Він в основному розглядає об'єкт, на який посилається __proto__властивість. Там він перевіряє, чи є власність доступною для об'єкта, на який посилається __proto__.
  • Якщо властивість не знаходиться на __proto__об’єкті, воно підніметься вгору по __proto__ланцюжку, аж доObject об'єкта.
  • Якщо він не зможе знайти властивість ніде на об'єкті та його prototypeланцюжку, він повернеться undefined.

Наприклад:

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

let mySelf = new Person('Willem');

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

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


7

У мене трапляється вчитися прототипу від You Don't Know JS: this & Object Prototypes , яка є чудовою книгою, щоб зрозуміти дизайн під ним і уточнити стільки помилок (саме тому я намагаюся уникати використання спадщини та подібних речей instanceof).

Але у мене те саме питання, що тут задавали люди. Кілька відповідей справді корисні та освічуючі. Я також хотів би поділитися своїми розуміннями.


Що таке прототип?

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

Як отримати прототип об’єкта?

через __proto__абоObject.getPrototypeOf

var a = { name: "wendi" };
a.__proto__ === Object.prototype // true
Object.getPrototypeOf(a) === Object.prototype // true

function Foo() {};
var b = new Foo();
b.__proto__ === Foo.prototype
b.__proto__.__proto__ === Object.prototype

Що таке prototype?

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

Коли ми створюємо функцію a, prototypeавтоматично створюється як спеціальне властивість увімкнено, aа код функції зберігається як constructorвключений prototype.

function Foo() {};
Foo.prototype // Object {constructor: function}
Foo.prototype.constructor === Foo // true

Я хотів би розглянути цю властивість як місце для зберігання властивостей (включаючи методи) об’єкта функції. Це також причина, чому функції утиліти в JS визначаються як Array.prototype.forEach(),Function.prototype.bind() ,Object.prototype.toString().

Навіщо підкреслювати властивість функції ?

{}.prototype // undefined;
(function(){}).prototype // Object {constructor: function}

// The example above shows object does not have the prototype property.
// But we have Object.prototype, which implies an interesting fact that
typeof Object === "function"
var obj = new Object();

Так Arary, Function, Objectвсі функції. Я повинен визнати, що це освіжає моє враження про JS. Я знаю, що функції є першокласним громадянином в JS, але здається, що він побудований на функціях.

Яка різниця між __proto__і prototype?

__proto__посилання працює на кожен об’єкт для посилання на його [[Prototype]]властивість.

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

З цими двома ми могли б подумки зіставити ланцюжок прототипу. Як показано на цьому малюнку:

function Foo() {}
var b = new Foo();

b.__proto__ === Foo.prototype // true
Foo.__proto__ === Function.prototype // true
Function.prototype.__proto__ === Object.prototype // true

7

 Прототип JavaScript проти __prototype__

'use strict'
function A() {}
var a = new A();
class B extends A {}
var b = new B();
console.log('====='); // =====
console.log(B.__proto__ === A); // true
console.log(B.prototype.__proto__ === A.prototype); // true
console.log(b.__proto__ === B.prototype); // true
console.log(a.__proto__ === A.prototype); // true
console.log(A.__proto__ === Function.__proto__); // true
console.log(Object.__proto__ === Function.__proto__); // true
console.log(Object.prototype === Function.__proto__.__proto__); // true
console.log(Object.prototype.__proto__ === null); // true

У JavaScript кожен об’єкт (функція теж об’єкт!) Має __proto__властивість, властивість посилається на його прототип.

Коли ми використовуємо newоператор з конструктором для створення нового об’єкта, __proto__властивість нового об'єкта буде встановлена ​​за допомогою конструктораprototype властивістю , тоді конструктор буде викликаний новим об'єктом, в цьому процесі "це" буде посиланням на новий об'єкт в області конструктора нарешті поверніть новий об’єкт.

Прототип конструктора є __proto__власністю, властивість конструктора - prototypeце робота з newоператором.

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

Ланцюг прототипу насправді є __proto__властивістю об'єкта посилатися на свій прототип, а __proto__властивість прототипу - посилатися на прототип прототипу тощо, аж до посилання на __proto__властивість прототипу Об'єкта, що посилається на null.

Наприклад:

console.log(a.constructor === A); // true
// "a" don't have constructor,
// so it reference to A.prototype by its ``__proto__`` property,
// and found constructor is reference to A

[[Prototype]]а __proto__майно насправді одне й те саме.

Ми можемо використовувати метод getPrototypeOf Object, щоб отримати щось прототип.

console.log(Object.getPrototypeOf(a) === a.__proto__); // true

Будь-яка написана нами функція може бути використана для створення об'єкта з newоператором, тому будь-яка з цих функцій може бути конструктором.


6

Ще один хороший спосіб зрозуміти це:

var foo = {}

/* 
foo.constructor is Object, so foo.constructor.prototype is actually 
Object.prototype; Object.prototype in return is what foo.__proto__ links to. 
*/
console.log(foo.constructor.prototype === foo.__proto__);
// this proves what the above comment proclaims: Both statements evaluate to true.
console.log(foo.__proto__ === Object.prototype);
console.log(foo.constructor.prototype === Object.prototype);

Лише після того, як IE11 __proto__підтримується. До цієї версії, такі як IE9, ви могли б використовувати , constructorщоб отримати __proto__.


Тільки щоб я написав це навпаки: foo .__ proto__ === foo.constructor.prototype
epeleg

6

прототип

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

__proto__використовується в ланцюзі пошуку для вирішення методів, властивостей. коли об’єкт створений (використовуючи функцію конструктора з новим ключовим словом), __proto__встановлюється (Constructor) Function.prototype

function Robot(name) {
    this.name = name;
}
var robot = new Robot();

// the following are true   
robot.__proto__ == Robot.prototype
robot.__proto__.__proto__ == Object.prototype

Ось моє (уявне) пояснення, щоб очистити плутанину:

Уявіть, що існує уявний клас (креслення / виріз cookie), пов'язаний з функцією. Цей уявний клас використовується для інстанціювання об'єктів. prototypeце механізм розширення (метод розширення в C # або розширення Swift) для додавання речей до цього уявного класу.

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

Сказане можна уявити як:

// imaginary class
class Robot extends Object{

    static prototype = Robot.class  
    // Robot.prototype is the way to add things to Robot class
    // since Robot extends Object, therefore Robot.prototype.__proto__ == Object.prototype

    var __proto__;

    var name = "";

    // constructor
    function Robot(name) {

        this.__proto__ = prototype;
        prototype = undefined;

        this.name = name;
    }

} 

Тому,

var robot = new Robot();

robot.__proto__ == Robot.prototype
robot.prototype == undefined
robot.__proto__.__proto__ == Object.prototype

Тепер додаємо метод до prototypeроботи:

Robot.prototype.move(x, y) = function(x, y){ Robot.position.x = x; Robot.position.y = y};
// Robot.prototype.move(x, y) ===(imagining)===> Robot.class.move(x, y)

Сказане можна уявити як розширення класу Robot:

// Swift way of extention
extension Robot{
    function move(x, y){    
        Robot.position.x = x; Robot.position.y = y
    }
}

Які в свою чергу,

// imaginary class
class Robot{

    static prototype = Robot.class // Robot.prototype way to extend Robot class
    var __proto__;

    var name = "";

    // constructor
    function Robot(name) {

        this.__proto__ = prototype;
        prototype = undefined;

        this.name = name;
    }

    // added by prototype (as like C# extension method)
    function move(x, y){ 
        Robot.position.x = x; Robot.position.y = y
    };
}

все ще думаючи про більш узгоджені назви для __proto__і прототипу. можливо, прототип і успадкування?
Дмитро

Я б сказав, prototypeі __proto__обох слід уникати. Зараз у нас клас, і мені подобається OOP.
Хасан Тарек

Проблема полягає в тому, що клас відносно новий, і він не підтримується дійсно зручними двигунами, такими як Microsoft JScript (приємно мати при роботі над C і потрібен швидкий і брудний движок скриптів, який завжди є), і Nashorn javascript (який поставляється з усіма нові установки Java під jjs, і це приємний спосіб введення Java в чисте динамічне середовище, де вам не потрібно постійно перекомпілювати речі). Річ у тім, що якби клас був цукровим, це не було б проблемою, але це не так, він пропонує речі, які неможливі без них у старих версіях js. Як і розширення "Функції".
Дмитро

Врешті-решт ми отримаємо підтримку. Я забудова розробника, тому у мене немає проблем, кодую в js рідко.
Хассан Тарек

і успадкування статичних членів таким чином, що додавання нових / видалення статичних членів від батьків помічається дитиною (що я не можу придумати спосіб зробити на JScript, який не пропонує Object.assign / __ proto __ / getPrototypeOf, тож ви доведеться повозитися з коренем Object.prototype, щоб імітувати його)
Дмитро

4

Простіше кажучи:

> var a = 1
undefined
> a.__proto__
[Number: 0]
> Number.prototype
[Number: 0]
> Number.prototype === a.__proto__
true

Це дозволяє приєднати властивості до X.prototype ПІСЛЯ об'єктів типу X було створено, і вони все одно отримають доступ до цих нових властивостей через посилання __proto__, яке використовує Javascript-двигун для проходження ланцюга прототипу.


4

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

__proto__ - це властивість аксесуара (функція get and set), яка розкриває внутрішній прототип об'єкта, через який він має доступ.

Список літератури:

  1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype
  2. http://www.w3schools.com/js/js_object_prototypes.asp

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


Object.prototypeне є властивістю об'єкта буквально, намагаючись роздрукувати {}.prototypeповернення невизначеними; однак до нього можна отримати доступ через {}.__proto__, який повертається Object.prototype.
подвійнийокт

3

Я знаю, я спізнююсь, але дозвольте спробувати спростити це.

Скажімо, є функція

    function Foo(message){

         this.message = message ; 
     };

     console.log(Foo.prototype);

Функція Foo матиме пов'язаний прототип. Отже, кожного разу, коли ми створюємо функцію в JavaScript, у неї завжди є об'єкт прототипу, пов'язаний з нею.

Тепер давайте продовжимо та створимо два об’єкти за допомогою функції Foo.

    var a = new Foo("a");
    var b = new Foo("b");
    console.log(a.message);
    console.log(b.message);
  1. Тепер у нас є два об’єкти, об’єкт a і об'єкт b. Обидва створені за допомогою конструктора Foo. Майте на увазі, конструктор тут просто слово.
  2. Обидва об'єкти a і b мають властивість копії повідомлення.
  3. Ці два об'єкти a і b пов'язані з прототипом об'єкта конструктора Foo.
  4. На об'єктах a і b ми можемо отримати доступ до прототипу Foo, використовуючи прото- властивість у всіх браузерах, а в IE ми можемо використовувати Object.getPrototypeOf (a) або Object.getPrototypeOf (b)

Тепер Foo.prototype, a. прото , і б. proto - позначає один і той же об'єкт.

    b.__proto__ === Object.getPrototypeOf(a);
    a.__proto__ ===  Foo.prototype;
    a.constructor.prototype  === a.__proto__;

все вище повернеться правдою.

Як ми знаємо, в JavaScript властивості можна додавати динамічно. Ми можемо додати властивість до об’єкта

    Foo.prototype.Greet = function(){

         console.log(this.message);
    }
    a.Greet();//a
    b.Greet();//b
    a.constructor.prototype.Greet();//undefined 

Як ви бачите, ми додали метод Greet () у Foo.prototype, але він доступний у a і b або будь-якому іншому об'єкті, побудованому за допомогою Foo.

Під час виконання a.Greet () JavaScript спочатку здійснить пошук Greet в об'єкті a у списку властивостей. Якщо не знайти, він підніметься в прото- ланцюжку a. З а. proto і Foo.prototype - той самий об'єкт, JavaScript знайде метод Greet () та виконає його.

Сподіваюсь, тепер прототип і proto трохи спрощені.


3

Пояснювальний приклад:

function Dog(){}
Dog.prototype.bark = "woof"

let myPuppie = new Dog()

Тепер у myPupppie є __proto__властивість, яка вказує на Dog.prototype.

> myPuppie.__proto__
>> {bark: "woof", constructor: ƒ}

але myPuppie НЕ має властивості прототипу.

> myPuppie.prototype
>> undefined

Отже, __proto__mypuppie - це посилання на властивість .prototype функції конструктора, яке було використано для інстанціювання цього об’єкта (і поточний об'єкт myPuppie має відношення до цього "делегувати"__proto__ об'єкта), тоді як .prototype властивість myPuppie просто відсутня (оскільки ми його не встановлювали).

Добре пояснення MPJ тут: proto vs prototype - Створення об'єктів у JavaScript


3

Я зробив для себе невеликий малюнок, який представляє такий фрагмент коду:

var Cat = function() {}
var tom = new Cat()

Розуміння __proto__ та прототипу

У мене є класичний фон OO, тому було корисно представити ієрархію таким чином. Щоб прочитати цю діаграму, розгляньте прямокутники на зображенні як об’єкти JavaScript. І так, функції також є об'єктами. ;)

Об'єкти в JavaScript мають властивості і __proto__є лише одним з них.

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

Кореневим об'єктом у JavaScript є, Object.prototypeа всі інші об'єкти є нащадками цього. __proto__Властивість кореневого об'єктаnull , який являє собою кінець успадкування ланцюга.

Ви помітите, що prototypeце властивість функцій. Catє функцією, але також є Functionі Objectє (рідною) функцією.tomне є функцією, тому вона не має цієї властивості.

Ідея цієї властивості полягає в тому, щоб вказати на об'єкт, який буде використовуватися в побудові, тобто коли ви викликаєте newоператора цієї функції.

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

Дійсно, коли ми створюємо tomоб'єкт за допомогою new Cat(), створений об’єкт матиме __proto__властивість, встановлену для prototypeоб'єкта функції конструктора.

Зрештою, давайте трохи пограємо з цією діаграмою. Наступні твердження вірні:

  • tom.__proto__властивість вказує на той самий об'єкт, що і Cat.prototype.

  • Cat.__proto__вказує на Function.prototypeоб’єкт, як Function.__proto__і Object.__proto__робити.

  • Cat.prototype.__proto__і tom.__proto__.__proto__вказують на той самий об’єкт, і це Object.prototype.

Ура!


Дуже добре пояснено!
UI

@theshinylight, tom.__proto__і Cat.prototypeвони суворо рівні, Отже, tom.__proto__ === Cat.prototype і Cat.prototype === tom.__proto__правдиві. Отже, що ви мали на увазі під стрілкою на зображенні ??
aXuser264

Чорна стрілка (якщо ви посилаєтесь на неї) не має особливого значення, крім властивості об'єкта. Так само prototypeє власністю Catоб'єкта (з вашого запитання).
theshinylight

2

ВИЗНАЧЕННЯ

(число в круглих дужках () - це "посилання" на код, який написано нижче)

prototype- об'єкт, який складається з:
=> функцій (3) цього конкретного ConstructorFunction.prototype(5), доступних кожному об'єкту (4), створеному або створюваному за допомогою цієї функції конструктора (1)
=> сама функція конструктора (1 )
=> __proto__цього конкретного об'єкта (прототипного об'єкта)

__proto__(dandor proto?) - посилання між будь-яким об'єктом (2), створеним за допомогою певної функції конструктора (1), а властивості об'єкта-прототипу (5) цього конструктора, що дозволяє кожному створеному об'єкту (2) отримати доступ до функцій прототипу та методи (4) ( __proto__за замовчуванням включений у кожен об'єкт JS)

КЛАФІКАЦІЯ КОДУ

1.

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

2.

    var John = new Person(‘John’, 37);
    // John is an object

3.

    Person.prototype.getOlder = function() {
        this.age++;
    }
    // getOlder is a key that has a value of the function

4.

    John.getOlder();

5.

    Person.prototype;

1

Я спробую пояснити 4-й клас:

Речі дуже прості. А prototypeє прикладом того, як щось потрібно будувати. Тому:

  • Я functionі будую нові об'єкти, подібні до моїхprototype

  • Я є, objectі я був побудований, використовуючи свій __proto__приклад

доказ :

function Foo() { }

var bar = new Foo()

// `bar` is constructed from how Foo knows to construct objects
bar.__proto__ === Foo.prototype // => true

// bar is an instance - it does not know how to create objects
bar.prototype // => undefined

1
Ні, ні prototypeані в __proto__будь-який час не використовуються як креслення або так для створення будь-якого об'єкта. Це міф, введений розмитим classсинтаксисом та його попередниками. Як йдеться у повідомленні відповіді, він просто використовується для ланцюжка пошуку та у випадку prototypeідентифікації, що constructorвикористовується із new(що є частиною механізму, який претендує на клас, який заплутує багатьох користувачів, включаючи мене).
Крістоф Келін

Перший пункт повинен бути "Я функція, і я будую нові об'єкти, які будуть делеговані до мого прототипу"
Нітін Ядхав

1

Кожна створена вами функція має властивість, яку називають prototype, і вона починає своє життя як порожній об'єкт. Це властивість не приносить користі, поки ви не будете використовувати цю функцію як конструкторську функцію, тобто з ключовим словом "new".

Це часто плутають із __proto__властивістю об’єкта. Деякі можуть заплутатися, за винятком того, що prototypeвластивість об'єкта може змусити їх стати прототипом об'єкта. Але це не так. prototypeвикористовується для отримання__proto__ об'єкта, створеного з конструктора функцій.

У наведеному вище прикладі:

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

var eve = new Person("Eve");

console.log(eve.__proto__ == Person.prototype) // true
// this is exactly what prototype does, made Person.prototype equal to eve.__proto__

Сподіваюся, це має сенс.


1
prototypeне використовується для створення __proto__об'єкта. __proto__, при зверненні просто надає посилання на prototypeоб'єкт.
подвійнийокт

1

Що з використанням __proto__статичних методів?

function Foo(name){
  this.name = name
  Foo.__proto__.collection.push(this)
  Foo.__proto__.count++

}

Foo.__proto__.count=0
Foo.__proto__.collection=[]

var bar = new Foo('bar')
var baz = new Foo('baz')

Foo.count;//2
Foo.collection // [{...}, {...}]
bar.count // undefined

Саме тому відповідь на " __proto__VS. prototypeу JavaScript" ?
Андреас

добре це чи про Foo.collection.push (це) Foo.count ++
Селва Ганапаті

1

(function(){ 
      let a = function(){console.log(this.b)};
      a.prototype.b = 1;
      a.__proto__.b = 2;
      let q = new a();
      console.log(a.b);
      console.log(q.b) 
    })()

Спробуйте цей код, щоб зрозуміти


1

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

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

Суть у цьому: __proto__це ім'я, на яке посилається прототипний об'єкт, і prototypeє власне прототипним об'єктом.

Це як сказати:

let x = {name: 'john'};

x- це ім'я об'єкта (вказівник) і {name: 'john'}є фактичним об'єктом (значення даних).

ПРИМІТКА. Це просто масово спрощений натяк на те, як вони пов'язані на високому рівні.

Оновлення: Ось простий конкретний приклад javascript для кращої ілюстрації:

let x = new String("testing") // Or any other javascript object you want to create

Object.getPrototypeOf(x) === x.__proto__; // true

Це означає , що , коли Object.getPrototypeOf(x)отримує нас фактичне значення x(яке є його прототипом), є саме те , що __proto__з xвказує на. Тому __proto__дійсно вказує на прототип x. Таким чином, __proto__посилання x(покажчик на x), і prototypeє значенням x(його прототип).

Я сподіваюся, що це зараз трохи зрозуміло.


1

Це дуже важливе питання, актуальне для всіх, хто хоче зрозуміти прототипне успадкування. З того, що я розумію, прототип призначається за замовчуванням, коли об’єкт створюється новим з функції, оскільки функція має об’єкт прототипу за визначенням:

function protofoo(){
}
var protofoo1 = new protofoo();
console.log(protofoo.prototype.toString()); //[object Object]

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

var foo={
  check: 10
};
console.log(foo.__proto__); // empty
console.log(bar.prototype); //  TypeError
foo.__proto__ = protofoo1; // assigned
console.log(foo.__proto__); //protofoo

Ми можемо використовувати Object.create для явного зв'язку об'єкта.

// we can create `bar` and link it to `foo`
var bar = Object.create( foo );
bar.fooprops= "We checking prototypes";
console.log(bar.__proto__); // "foo"
console.log(bar.fooprops); // "We checking prototypes"
console.log(bar.check); // 10 is delegated to `foo`

0

__proto__є базою для побудови prototypeта функцією конструктора, наприклад: function human(){}має, prototypeяку поділяють через __proto__в новому екземплярі функції конструктора. Детальніше читайте тут


@Derick Daniel: не впевнений, чому ти проголосував за це, але редакцію, яку ти зробив, не те, що я намагався передати. Відредагував його далі для отримання більшого дозволу :).
Jyoti Duhan

Jyoti, я не проголосував вашу відповідь, це робив хтось інший, я її просто відредагував :)
Фрілансер,

0

Як це правильно сказано

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

( new Foo ).__proto__ === Foo.prototype;
( new Foo ).prototype === undefined;

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

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

Розглянемо наступний приклад:

function Human(){
    this.speed = 25;
}

var himansh = new Human();

Human.prototype.showSpeed = function(){
    return this.speed;
}

himansh.__proto__ === Human.prototype;  //true
himansh.showSpeed();    //25

//now re-initialzing the Human.prototype aka changing its memory location
Human.prototype = {lhs: 2, rhs:3}

//himansh.__proto__ will still continue to point towards the same original memory location. 

himansh.__proto__ === Human.prototype;  //false
himansh.showSpeed();    //25

-1

моє розуміння таке: __proto__ і прототип усі подаються для ланцюгової техніки прототипу. Різниця полягає в тому, що функції, названі підкресленням (наприклад, __proto__), взагалі не спрямовані на те, щоб розробники посилалися явно. Іншими словами, вони є лише для деяких механізмів, таких як успадкування і т. д. вони є "бек-ендом". але функції, названі без підкреслення, призначені для явного виклику, вони є "передній".


3
Є більше __proto__і prototype, ніж просто іменування. Вони можуть або не можуть вказувати на один і той же об’єкт. Дивіться відповідь @zyklus.
demisx

1
@demisx Ви, звичайно, сказали, що це правильно, але, на мою думку, різниця імен піддається контрасту функціоналу.
Beicai

Не достатньо лише сказати "згідно з вашим розумінням", особливо коли були надані інші хороші відповіді раніше ...
ProfNandaa

-3

!!! ЦЕ НАЙКРАЩЕ ПОЯСНЕННЯ В СВІТІ !!!!!

var q = {}
var prototype = {prop: 11}

q.prop // undefined
q.__proto__ = prototype
q.prop // 11

у конструкторах функцій JavaScript-движок викликає це q.__proto__ = prototypeавтоматично, коли ми пишемо new Class, і в __proto__набір опорClass.prototype

function Class(){}
Class.prototype = {prop: 999} // set prototype as we need, before call new

var q = new Class() // q.__proto__ = Class.prototype
q.prop // 999

Насолоджуйтесь%)

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