__proto__ VS. прототип в 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__, установленным в null. Мне также нравится, как на диаграмме создается трехуровневая концептуальная визуализация того, как программист воспринимает объекты как 1. экземпляры, 2. конструкторы, 3. прототипы, которые конструкторы связывают с этими экземплярами при создании экземпляра с помощью нового ключевого слова.
Джон Сондерсон

Диаграмма имеет смысл сразу после того, как вы смотрите что-то вроде youtube.com/watch?v=_JJgSbuj5VI , кстати
mlvljr

И теперь, когда я прочитал ответы, чувствую себя обязанным действительно рекомендовать вышеупомянутое видео, поскольку оно действительно имеет кристально чистое (и не WTFy) объяснение того, что происходит :)
mlvljr

Ответы:


766

__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
Нико Беллик

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

336

prototypeявляется свойством объекта Function. Это прототип объектов, созданных этой функцией.

__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__чтобы иметь своего рода вызываемый объект экземпляра.
kzh

myPoint .__ proto __. constructor.prototype == Point.prototype
Франциско

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

myFn.__proto__ = {foo: 'bar'}
kzh

Я думаю, что у меня есть ваша точка зрения.
ComicScrip

120

Свойство прототипа создается при объявлении функции.

Например:

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

Person.prototypeсвойство создается внутри, как только вы объявляете вышеуказанную функцию. Многие свойства могут быть добавлены в Person.prototype, которые совместно используются экземплярами Person, созданными с использованием new 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это a, 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)который возвращает истину, если объект является экземпляром класса.


2
Мне было интересно, почему prototypeобъект был создан внутренне в первую очередь? Можно ли просто назначить статические методы самому объекту функции. например function f(a){this.a = a}; f.increment = function(){return ++this.a}? Почему этот способ не был выбран вместо добавления методов к prototypeобъекту? Это будет работать, если f.__proto__ = gгде g - базовый класс.
abhisekp

Возможно, prototypeобъект был выбран для совместного использования, потому что только исключительные свойства конструктора функции могут быть сохранены в объекте конструктора функции.
abhisekp

1
На самом деле, это было бы неразберихой, потому что instanceofэто привело ({}) instanceof Function === trueбы к невозможности провести различие между прототипами, если prototypeсвойство будет удалено.
abhisekp

@abhisekp Что вы подразумеваете под этим: «Это будет работать, если f .__ proto__ = g, где g - базовый класс». Я не знаю, имеет ли это какое-то значение, которое я не понимаю, но если бы вы добавили свойства и методы таким образом, то когда вы использовали newключевое слово для создания экземпляра, свойства и методы не были бы скопированы над.
doubleOrt

67

Хороший способ думать об этом ...

prototypeиспользуется constructor()функциями. Это должно было действительно называться как-то "prototypeToInstall", так как это то, что есть.

и __proto__является ли этот «установленный прототип» на объекте (который был создан / установлен на объекте из указанной constructor()функции)


2
Я проголосовал за него, но, возможно, причина его была в том, что утверждение «прототип используется функциями constructor ()» может звучать так, как если бы не функции конструктора отсутствовали, что не так, однако, кроме того, что это не является нашей целью сейчас можно заметить, что каждая функция потенциально является конструктором, если
вызывается

2
Пожалуйста, измените « constructor()функции» на «функции конструктора», так как это может привести к путанице с « __proto__.constructor()функциями». Я считаю это важным, поскольку __proto __. Конструктор фактически не вызывается, когда используется newключевое слово.
Александр Гончий

1
Утверждение, что « прототип используется функциями constructor () », говорит лишь о части важного факта, но говорит о нем таким образом, что читатели могут думать, что это весь факт. прототип создается для каждого объявления функции в Javascript независимо от того, как эта функция будет вызываться в будущем - с ключевым словом new или без него ; Прототип объявленной функции указывает на литерал объекта.
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) в качестве его контекста (this), поэтому nameсвойство, переданное как «JavaScript» (которое добавляется this), добавляется к вновь созданному объекту.
  4. Он возвращает вновь созданный объект в (созданный на шаге # 1), поэтому var bприсваивается вновь созданному объекту.

Теперь, если мы добавим a.prototype.car = "BMW"и сделаем b.car, появится вывод «BMW».

это потому, что когда JavaScript выполнял этот код, он искал carсвойство on b, он не находил используемый тогда JavaScript b.__proto__(который был создан для указания на «a.prototype» на шаге # 2) и находил carсвойство, поэтому возвращал «BMW».


2
1. constructorне возвращается a()! Это возвращается a. 2. __proto__возвращает Object.prototype, а не корневой объект в Javascript.
doubleOrt

1
Это отличный ответ!
Джон Рэймон

+1 это лучший ответ для объяснения того, что на самом деле представляет собой прототип (объект с двумя свойствами) и как Javascript выполняет каждый фрагмент кода. Эта информация на удивление трудно найти.
java-addict301

53

Прототип VS. __proto__ VS. [[Прототип]]

При создании функции объект свойства с именем prototype создается автоматически (вы сами его не создавали) и присоединяется к объекту функции (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__на самом деле это функция получения , принадлежащая нативному объекту JavaScript. Он возвращает внутренне-частную связь прототипа любой thisпривязки (возвращает [[Prototype]]of 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
Лиор Элром

31

Чтобы сделать это немного яснее в дополнение к вышеупомянутым отличным ответам:

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

var eve = new Person("Eve");

eve.__proto__ == Person.prototype //true

eve.prototype  //undefined

Экземпляры имеют __proto__ , классы имеют прототип .


13

В JavaScript функция может использоваться как конструктор. Это означает, что мы можем создавать объекты из них, используя ключевое слово new. Каждая функция конструктора поставляется со встроенным объектом, связанным с ними. Этот встроенный объект называется прототипом.Instances of a constructor function use __proto__ to access the prototype property of its constructor function.

схема прототипа

  1. Сначала мы создали конструктор: function Foo(){}. Чтобы быть понятным, Foo это просто еще одна функция. Но мы можем создать объект из него с новым ключевым словом. Вот почему мы называем это функцией конструктора

  2. Каждая функция имеет уникальное свойство, которое называется свойством прототипа. Итак, функция Constructor Fooимеет свойство prototype, которое указывает на его прототип Foo.prototype(см. Изображение).

  3. Функции-конструкторы сами являются функцией, которая является экземпляром системного конструктора, называемого конструктором [[Function]]. Таким образом, мы можем сказать, что function Fooон построен конструктором [[Function]]. Итак, __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__х и у, таким образом, указывает на Foo.prototype.


Просто чтобы прояснить: у экземпляров нет свойства .prototype? Только функция конструктора верно? ... Таким образом, разница между экземпляром и его функцией конструктора заключается в том, что функции конструктора имеют оба объекта: 1. proto 2. .prototype, в то время как экземпляры имеют только свойство .__ proto__ ... правильно?
Shaz

@ Шаз, ты прав. instances использует свои proto для доступа к свойству prototype своей функции конструктора.
АЛ-зами

Но почему, почему, когда вы пишете: var car = Object.create (Vehicle); вы получите автомобиль .__ proto__ = Автомобиль, НО вы также получите свойство car.prototype, которое указывает на Vehicle.prototype?
Shaz

@shaz Можете ли вы предоставить jsfiddle, чтобы я мог представить ситуацию?
AL-zami

1
здесь car.prototype является унаследованным свойством. Автомобиль наследует свойство «прототип» от функции транспортного средства. так car.prototype === vehicle.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 функции также являются объектами. Объекты могут иметь свойства, а свойство по умолчанию любой функции - это одно свойство с именем prototype.

Затем, когда эта функция используется в качестве функции-конструктора, объект, созданный из нее, получит свойство с именем __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 Not 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она автоматически создается как специальное свойство on aи сохраняет код функции как constructoron 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свойством конструктора , тогда конструктор будет вызывать новый объект, в этом процессе «this» будет ссылкой на новый объект в области конструктора, наконец, верните новый объект.

Прототип конструктора - это __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 объекта, чтобы получить прототип чего-либо.

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

прототип

Прототип является свойством функции. Это план создания объектов с использованием этой функции (конструктора) с ключевым словом new.

__proto__используется в цепочке поиска для разрешения методов, свойств. при создании объекта (с использованием функции конструктора с новым ключевым словом) __proto__устанавливается значение (конструктор) 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

Вот мое (воображаемое) объяснение, чтобы убрать путаницу:

Представьте себе, что существует некий воображаемый класс (планер / резак), связанный с функцией. Этот воображаемый класс используется для создания объектов. prototypeэто механизм расширения (метод расширения в C # или Swift Extension) для добавления вещей в этот воображаемый класс.

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__другого следует избегать. У нас сейчас класс, и мне нравится ООП.
Хасан Тарек

проблема в том, что класс является относительно новым и не поддерживается действительно удобными движками, такими как Microsoft JScript (приятно иметь при работе на C и нуждаются в быстром и грязном скриптовом движке, который всегда есть) и nashorn javascript (который поставляется со всеми новые установки Java под jjs - это хороший способ поместить Java в чистую динамическую среду, где вам не нужно постоянно перекомпилировать вещи). Дело в том, что если бы класс был сахаром, это не было бы проблемой, но это не так, он предлагает вещи, которые невозможны без них в старых версиях js. Как расширение «Функция».
Дмитрий

Со временем мы получим поддержку. Я бэкэнд-разработчик, поэтому у меня нет проблем, я редко пишу в js.
Хасан Тарек

и наследование статических элементов таким образом, что добавление новых / удаление статических элементов из parent замечено дочерним процессом (что я не могу придумать, как сделать это на 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. Объекты AFTER типа X были созданы, и они по-прежнему будут получать доступ к этим новым свойствам через ссылку __proto__, которую Javascript-движок использует для прохождения по цепочке прототипов.


4

Prototype или Object.prototype - это свойство литерала объекта. Он представляет объект- прототип Object, который вы можете переопределить, чтобы добавить дополнительные свойства или методы дальше по цепочке прототипов.

__proto__ - это свойство метода доступа (функция get и 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возвращает undefined; однако, это может быть получено через {}.__proto__, который возвращает Object.prototype.
DoubleOrt

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, используя свойство proto во всех браузерах, а в IE мы можем использовать Object.getPrototypeOf (a) или Object.getPrototypeOf (b).

Теперь, Foo.prototype, a. прото и б. Прото все обозначает один и тот же объект.

    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 в списке свойств. Не найдя, он перейдет в прото- цепочку. Так как Прото и Foo.prototype это один и тот же объект, JavaScript найдет метод Greet () и выполнит его.

Надеюсь, теперь прототип и прото немного упрощены.


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 против 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.

Ура!


Очень хорошо объяснил!
Пользовательский интерфейс StackOverflow

@theshinylight, tom.__proto__и Cat.prototypeстрого равны, так что, tom.__proto__ === Cat.prototype и Cat.prototype === tom.__proto__это правда. Итак, что вы имели в виду под стрелкой на изображении ??
aXuser264

Черная стрелка (если вы на нее ссылаетесь) не имеет особого значения, кроме свойства объекта. Так же prototypeкак и свойство Catобъекта (из вашего вопроса).
прошлый вечер

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объект.
doubleOrt

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 (this) Foo.count ++
Selva

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(){}has, prototypeкоторая используется совместно __proto__в новом экземпляре функции конструктора. Более подробно читайте здесь


@Derick Daniel: не уверен, почему вы проголосовали за это, но вы не пытались передать правку, которую вы сделали. Отредактировал это далее для большего зазора :).
Джиоти Духан

Jyoti, я не голосовал против твой ответ, кто-то другой сделал, я только отредактировал это :)
Фрилансер

0

Как это правильно сказано

__proto__фактический объект, который используется в цепочке поиска для разрешения методов и т. д .; прототип - это объект, который используется для создания __proto__при создании объекта с новым:

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

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

Если мы изменим расположение в памяти прототипа функции конструктора, __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__) вообще не предназначены для разработчиков, вызываемых явно. другими словами, они просто для некоторых механизмов, таких как наследование и т. д., они являются «бэк-эндами». но функции, названные без подчеркивания, предназначены для вызова в явном виде, они 'front-end'.


3
Есть больше __proto__и prototype, чем просто именование. Они могут указывать или не указывать на один и тот же объект. Смотрите ответ @zyklus.
demisx

1
@demisx, конечно, вы сказали, что это правильно, но мое мнение, что разница в именах выявила контраст функциональности.
Beicai

Недостаточно просто заявить «в соответствии с вашим пониманием», особенно если раньше были предоставлены другие хорошие ответы ...
ПрофНандаа,

-3

!!! Это лучшее объяснение в мире !!!!!

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

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

в конструкторах функций Javascript Engine вызывает это 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.