Как на JavaScript.прототип?

Я не в динамических языках программирования, но я написал свою долю кода JavaScript. Я никогда не разбирался в этом программировании на основе прототипов, кто-нибудь знает, как это работает?

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

Я помню много дискуссий, которые у меня были с людьми некоторое время назад (я не совсем уверен, что я делаю), но, как я понимаю, нет концепции класса. Это просто объект, и экземпляры этих объектов являются клонами исходного, правильно?

но какова точная цель этого ".прототип" свойство в 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

эти горки очень помогло.

23 ответов


каждый объект JavaScript имеет внутреннее свойство, называемое [[прототип]]. Если вы ищете недвижимость через obj.propName или obj['propName'] и объект не имеет такого свойства - которое можно проверить через obj.hasOwnProperty('propName') - среда выполнения ищет свойство в объекте, на который ссылается [[Prototype]]. Если прототип-объект также не имеет такого свойства, его прототип проверяется в свою очередь, таким образом, прогуливаясь по исходному объекту прототип-цепь пока не будет найдено или его конец достигнут.

некоторые реализации JavaScript позволяют прямой доступ к свойству [[Prototype]], например, через нестандартное свойство с именем __proto__. В общем случае можно установить прототип объекта только во время создания объекта: если вы создаете новый объект через new Func(), свойство [[Prototype]] объекта будет установлено на объект, на который ссылается Func.prototype.

это позволяет моделировать классы в JavaScript, хотя система наследования JavaScript - как мы видели-прототипические, а не классовые:

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


в языке, реализующем классическое наследование, таком как Java, C# или c++, вы начинаете с создания класса-схемы для ваших объектов-а затем вы можете создать новые объекты из этого класса или вы можете расширить класс, определив новый класс, который увеличивает исходный класс.

в JavaScript вы сначала создаете объект (нет понятия класса), затем вы можете увеличить свой собственный объект или создать из него новые объекты. Это не сложно, но немного чужеродно и трудно усваивается для кого-то, кто привык к классическому способу.

пример:

//Define a functional object to hold persons in JavaScript
var Person = function(name) {
  this.name = name;
};

//Add dynamically to the already defined object a new getter
Person.prototype.getName = function() {
  return this.name;
};

//Create a new object of type Person
var john = new Person("John");

//Try the getter
alert(john.getName());

//If now I modify person, also John gets the updates
Person.prototype.sayMyName = function() {
  alert('Hello, my name is ' + this.getName());
};

//Call the new method on john
john.sayMyName();

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

//Create a new object of type Customer by defining its constructor. It's not 
//related to Person for now.
var Customer = function(name) {
    this.name = name;
};

//Now I link the objects and to do so, we link the prototype of Customer to 
//a new instance of Person. The prototype is the base that will be used to 
//construct all new instances and also, will modify dynamically all already 
//constructed objects because in JavaScript objects retain a pointer to the 
//prototype
Customer.prototype = new Person();     

//Now I can call the methods of Person on the Customer, let's try, first 
//I need to create a Customer.
var myCustomer = new Customer('Dream Inc.');
myCustomer.sayMyName();

//If I add new methods to Person, they will be added to Customer, but if I
//add new methods to Customer they won't be added to Person. Example:
Customer.prototype.setAmountDue = function(amountDue) {
    this.amountDue = amountDue;
};
Customer.prototype.getAmountDue = function() {
    return this.amountDue;
};

//Let's try:       
myCustomer.setAmountDue(2000);
alert(myCustomer.getAmountDue());

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

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

хотя, как сказано, я не могу вызвать setAmountDue (), getAmountDue() на человека.

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

я играю роль учителя JavaScript, и концепция прототипа всегда была спорной темой для обсуждения, когда я преподаю. Мне потребовалось некоторое время, чтобы придумать хороший метод для уточнения концепции, и теперь в этом тексте я попытаюсь объяснить, как работает JavaScript .прототип работы.


это очень простой прототип на основе объектной модели, которая будет рассматриваться как образец во время объяснения, без комментариев еще:

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

есть некоторые важные моменты, которые мы должны рассмотреть прежде, чем идти через понятие прототипа.

1-как на самом деле работают функции JavaScript:

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

давайте мы хотим создать Person объектная модель. но на этом этапе я буду пытаться сделайте то же самое, не используя prototype и new ключевое слово.

Итак, на этом этапе functions, objects и this ключевое слово, это все, что у нас есть.

первый вопрос как this ключевое слово может быть полезно без использования new ключевое слово.

так ответить предположим, у нас есть пустой объект и две функции, такие как:

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

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

и теперь без использования new ключевое слово как мы могли бы использовать эти функции. Таким образом, JavaScript имеет 3 разных способа сделать это:

a. первый способ-просто вызвать функцию как обычную функцию:

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

в этом случае это будет текущий объект контекста, который обычно является глобальным прикрепить их объекту, как его свойства

-самый простой способ для этого нужно изменить пустой . Поэтому, чтобы убедиться, что вы можете сделать:

console.log(person.__proto__===propertiesObject); //true

но хитрый момент здесь в том, что у вас есть доступ ко всем свойствам, определенным в __proto__ на первом уровне person object (Подробнее читайте в сводной части).


как вы видите, используя любой из этих двух способов this было бы точно пункт в нашем my_person_prototype:

newObject.getName();

Си. затем он дает этот объект в конструктор,

мы можем сделать это с нашим образцом как:

Person.call(newObject, "George");

или

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

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

теперь конечный результат перед имитацией других шагов: Имя объекта: "Джордж"}


резюме:

в основном, когда вы используете новая ключевое слово для функции, вы вызываете это, и эта функция служит конструктором, поэтому, когда вы говорите:

new FunctionName()

JavaScript внутренне создает объект, пустой хэш, а затем он дает этот объект конструктору, тогда конструктор может делать все, что захочет, потому что этой внутри этого конструктора является объект, который был просто создан, а затем он дает вам этот объект, конечно, если вы не использовали оператор return в своей функции или если вы поставили return undefined; в конце тела функции.

поэтому, когда JavaScript идет искать свойство на объекте, первое, что он делает, это ищет его на этом объекте. И тогда есть секретное свойство [[prototype]] который у нас обычно есть, как __proto__ и это свойство является то, что JavaScript смотрит на следующий. И когда это смотрит через __proto__, поскольку это снова другой объект JavaScript, он имеет свой собственный __proto__ атрибут, он идет вверх и вверх, пока не дойдет до точки, где следующий __proto__ равно null. Точка является единственным объектом в JavaScript, что его __proto__ атрибут имеет значение null -


prototype позволяет создавать классы. если вы не используете prototype затем он становится статическим.

вот краткий пример.

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

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

где, как в приведенном ниже коде

function obj()
{
}

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

obj стал классом, который теперь может быть создан. Несколько экземпляров obj могут существовать, и все они имеют the


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

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

это четкая диаграмма, чтобы показать наследование JavaScript по цепочке прототипов

и

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

этот содержит пример с кодом и несколькими хорошими диаграммами.

цепочка прототипов в конечном итоге возвращается к объекту.прототип.

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

надеюсь, что вам также полезно понять цепочку прототипов JavaScript.


семь коанов прототипа


0) две разные вещи можно назвать "прототип":

  • свойство прототипа, как в obj.prototype

  • прототип внутреннее свойство, обозначаемое как [[Prototype]] в ES5.

    его можно получить через ES5 Object.getPrototypeOf().

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


1) эти понятия существуют, чтобы ответить на вопрос:

когда я делаю obj.property, где JS ищет .property?

интуитивно, классическое наследование должно влиять на поиск недвижимости.


2)

  • __proto__ используется для точечной . поиск свойств, как в obj.property.
  • .prototype is не используется для поиска напрямую, только косвенно, поскольку он определяет __proto__ при создании объекта с new.

порядок просмотра есть:

  • свойства obj.p = ... или Object.defineProperty(obj, ...)
  • свойства obj.__proto__
  • свойства obj.__proto__.__proto__ и так далее
  • если какой-нибудь __proto__ is null, return undefined.

это так называемый прототип цепи.

вы можете избежать . поиск с obj.hasOwnProperty('key') и Object.getOwnPropertyNames(f)


3) есть два основных способа set obj.__proto__:

  • new:

    var F = function() {}
    var f = new F()
    

    затем new установил:

    f.__proto__ === F.prototype
    

    этой где .prototype привыкает.

  • Object.create:

     f = Object.create(proto)
    

    устанавливает:

    f.__proto__ === proto
    

4) код:

var F = function() {}
var f = new F()

соответствует следующей схеме:

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

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


5) .constructor обычно наступает от F.prototype до . поиск:

f.constructor === F
!f.hasOwnProperty('constructor')
Object.getPrototypeOf(f) === F.prototype
F.prototype.hasOwnProperty('constructor')
F.prototype.constructor === f.constructor

когда мы пишем f.constructor, JavaScript делает . поиска так:

  • f нет .constructor
  • f.__proto__ === F.prototype и .constructor === F, так что берите это

результат f.constructor == F интуитивно правильно, так как F используется для создания f, например, установить поля, как в классических языках ООП.


6) классический синтаксис наследования может быть достигнут путем манипулирования цепочками прототипов.

на ES6 добавляет class и extends ключевые слова, которые являются просто синтаксическим сахаром для ранее возможной манипуляции прототипом сумасшествие.

class C {
    constructor(i) {
        this.i = i
    }
    inc() {
        return this.i + 1
    }
}

class D extends C {
    constructor(i) {
        super(i)
    }
    inc2() {
        return this.i + 2
    }
}
// Inheritance syntax works as expected.
(new C(1)).inc() === 2
(new D(1)).inc() === 2
(new D(1)).inc2() === 3
// "Classes" are just function objects.
C.constructor === Function
C.__proto__ === Function.prototype
D.constructor === Function
// D is a function "indirectly" through the chain.
D.__proto__ === C
D.__proto__.__proto__ === Function.prototype
// "extends" sets up the prototype chain so that base class
// lookups will work as expected
var d = new D(1)
d.__proto__ === D.prototype
D.prototype.__proto__ === C.prototype
// This is what `d.inc` actually does.
d.__proto__.__proto__.inc === C.prototype.inc
// Class variables
// No ES6 syntax sugar apparently:
// http://stackoverflow.com/questions/22528967/es6-class-variable-alternatives
C.c = 1
C.c === 1
// Because `D.__proto__ === C`.
D.c === 1
// Nothing makes this work.
d.c === undefined

упрощенная схема без всех предопределенных объектов:

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

каждый объект имеет внутреннее свойство, [[прототип]], связывая его с другим объектом:

object [[Prototype]] -> anotherObject

в традиционном javascript связанным объектом является prototype свойства функций:

object [[Prototype]] -> aFunction.prototype

некоторые среды выставляют [[прототип]] как __proto__:

anObject.__proto__ === anotherObject

при создании объекта создается ссылка [[Prototype]].

// (1) Object.create:
var object = Object.create(anotherObject)
// object.__proto__ = anotherObject

// (2) ES6 object initializer:
var object = { __proto__: anotherObject };
// object.__proto__ = anotherObject

// (3) Traditional JavaScript:
var object = new aFunction;
// object.__proto__ = aFunction.prototype

таким образом, эти утверждения эквивалентны:

var object = Object.create(Object.prototype);
var object = { __proto__: Object.prototype }; // ES6 only
var object = new Object;

A new заявление не показывает цель ссылки (Object.prototype); вместо этого цель подразумевается конструктором (Object).

помните:

  • каждый объект имеет ссылку, [[прототип]], иногда представляется как __proto__.
  • каждая функция имеет prototype собственность.
  • объекты, созданные с new связана с prototype свойство их конструктора.
  • если функция никогда не используется в качестве конструктора,prototype собственность пойдет неиспользованный.
  • Если вам не нужен конструктор, используйте

Javascript не имеет наследования в обычном смысле, но имеет цепочку прототипов.

прототип цепи

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

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

это также полезно для наследования, потому что цепочка прототипов может состоять из многих других объектов.


эта статья долго. Но я уверен, что это очистит большинство ваших запросов что касается" прототипического " характера наследования JavaScript. И даже больше. Пожалуйста, прочитайте полную статью.

JavaScript в основном имеет два типа типов данных

  • номера объектов
  • объекты

Non объекты

ниже для объекта типы данных

  • строка
  • число (включая NaN и бесконечность)
  • логические значения (true,false)
  • undefined

эти типы данных возвращаются после использования typeof на оператор

typeof на "строковый литерал" (или переменная, содержащая строковый литерал) === 'string'

typeof на 5 (или любой числовой литерал или переменная, содержащая числовой литерал или NaN или Infynity)==='количество'

typeof на правда (или false или переменная, содержащая правда или false) === 'boolean'

typeof на undefined (или неопределенная переменная или переменная, содержащая undefined) === 'undefined'

на строка, и boolean типы данных могут быть представлены как объекты и номера объектов.Когда они представлены в качестве объектов их тип всегда = = = 'object'. Мы вернемся к этому, как только поймем типы данных объекта.

объекты

типы данных объекта можно разделить на два типа

  1. функции объекты типа
  2. объекты не функционального типа

на функции объекты типа это те, которые возвращают строку '' С typeof на оператора. В эту категорию попадают все пользовательские функции и все встроенные объекты JavaScript,которые могут создавать новые объекты с помощью оператора new. Для EG.

  • объект
  • строка
  • Boolean
  • массив
  • набирается Массивы
  • RegExp
  • функции
  • все другие встроенные объекты, которые могут создавать новые объекты с помощью оператора new
  • функции UserDefinedFunction(){ /*пользовательский код */ }

так, typeof (Object) === typeof (String) === typeof на(количество) === typeof (Boolean) === typeof (Array) === typeof (RegExp) === typeof на(функция) === typeof (UserDefinedFunction) === ''

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

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")

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

созданные таким образом объекты все!--18-->объекты не функционального типа и возвратить их typeof на==='object'. Во всех этих случаях объект "а" не создавать объекты с помощью оператора new. Итак, следующее неверно

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

встроенный объект мат is typeof на==='object'. Следовательно, новый объект типа Math не может быть создан новым оператором.

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

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

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}

этой "прототип" собственность только в функции объекты типа (и никогда в объекты не функционального типа).

это так при создании нового объекта (с использованием оператора new) он наследует все свойства и методы из текущего объекта-прототипа функции конструктора, т. е. внутренняя ссылка создается в новом созданный объект, который ссылается на объект, на который ссылается текущий объект прототип функции конструктора.

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

  • все объекты (тип функции и Функции тип) имеют свойство "конструктор", которое по умолчанию ссылается на тип функции object/конструктор, который его создал.

  • каждый объект, который создается внутренне ссылается на объект, на который ссылается "прототип" свойства конструктора который его создал. Этот объект известен как created прототип объекта (который отличается от объектов типа функции свойство "prototype", на которое он ссылается). Таким образом, созданный объект может напрямую обращаться к методам и свойствам, определенным в объекте, на который ссылается свойство "прототип" конструктора (во время создания объекта).

  • An объекта (и, следовательно, его унаследованные имена свойств) можно получить с помощью


  • концепция prototypal наследство является одним из самых сложных для многих разработчиков. Давайте попробуем понять корень проблемы, чтобы понять prototypal inheritance лучше. Начнем с есть prototype. При входе the Tree.prototype, вы получаете...

    enter image description here

    если вы посмотрите на выше console.log() вывод, вы можете увидеть свойство конструктора на Tree.prototype и __proto__ тоже собственность. The __proto__ представляет prototype что это function базируется, и так как это просто JavaScript function С inheritance настройки еще, это относится к Object prototype что-то просто встроено в Яваскрипт...

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

    здесь есть такие вещи, как .toString, .toValue, .hasOwnProperty etc...

    __proto__ который был принес мой mozilla устарел и заменен Object.getPrototypeOf метод, чтобы получить object's prototype.

    enter image description here

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

    давайте добавим метод к нашему Tree prototype.

    enter image description here

    мы изменили Root и добавил function филиала к нему.

    enter image description here

    это означает, когда вы создаете instance of Tree вы можете называть это branch метод.

    enter image description here

    мы также можем добавить primitives или objects нашим Prototype.

    enter image description here

    добавьте child-tree нашим Tree.

    enter image description here

    здесь Child наследует prototype из дерева, то, что мы делаем здесь, использует Object.create() метод создания нового объекта на основе того, что вы передаете, вот он Tree.prototype. В этом случае мы устанавливаем прототип дочернего объекта на новый объект, который выглядит идентично Tree прототип. Далее мы устанавливаем Child's constructor to Child, если мы не он бы Tree().

    enter image description here

    Child теперь имеет свой собственный prototype, его __proto__ указывает на Tree и Tree's prototype указывает на основания Object.

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

    теперь вы создаете instance of Child и звонок branch который первоначально доступен в Tree. Мы на самом деле не определили наш branch на Child prototype. Но, в Root prototype от которого ребенок наследует.

    enter image description here

    в JS все не является объектом, все может действовать как объект.

    Javascript есть примитивы типа strings, number, booleans, undefined, null. их нет object(i.e reference types), но, конечно, может действовать как object. Давайте рассмотрим пример здесь.

    enter image description here

    в первой строке этого списка a primitive строковое значение присваивается name. Вторая строка лечит имя как object и звонки charAt(0) использование точечной нотации.

    вот что происходит за кулисами: // что за


    какова точная цель этого ".прототип " собственности?

    интерфейс к стандартным классам становится расширяемым. Например, вы используете Array class, и Вам также нужно добавить пользовательский сериализатор для всех ваших объектов массива. Потратите ли вы время на кодирование подкласса или используйте композицию или ... Свойство prototype решает эту проблему, позволяя пользователям контролировать точный набор членов/методов класса.

    думать прототипы как дополнительный vtable-указатель. Когда некоторые члены отсутствуют в исходном классе, прототип просматривается во время выполнения.


    это может помочь классифицировать цепи прототипов на две категории.

    считайте конструктор:

     function Person() {}
    

    значение Object.getPrototypeOf(Person) - это функция. На самом деле, это Function.prototype. С Person был создан как функция, он разделяет тот же объект функции прототипа, что и все функции. Это то же самое, что Person.__proto__, но это свойство не должно использоваться. Во всяком случае, с Object.getPrototypeOf(Person) вы эффективно поднимаетесь по лестнице того, что называется прототипом цепь.

    цепь в направлении вверх выглядит так:

    PersonFunction.prototypeObject.prototype (конечного пункта)

    важно то, что эта цепь-прототип имеет мало общего с объектами, которые Person can построить. Эти сконструированные объекты имеют свою собственную цепочку прототипов,и эта цепочка потенциально не может иметь близкого общего предка с вышеупомянутым.

    возьмите, например, это объект:

    var p = new Person();
    

    p не имеет прямого отношения прототипа-цепи с человек. У них другие отношения. Объект p имеет свою собственную цепочку прототипов. Используя Object.getPrototypeOf, вы найдете цепь следующим образом:

    pPerson.prototypeObject.prototype (конечного пункта)

    в этой цепочке нет объекта функции (хотя это может быть).

    так Person кажется, связано с двумя видами цепей, которые живут своей жизнью. Чтобы "перепрыгнуть" с одной цепи на другую, вы используете:

    1. .prototype: переход от цепочки конструктора к цепочке созданного объекта. Таким образом, это свойство определяется только для объектов функций (as new можно использовать только в функциях).

    2. .constructor: переход от цепочки созданного объекта к цепочке конструктора.

    вот визуальное представление двух задействованы прототипы цепочек, представленные в виде столбцов:

    enter image description here

    в итоге:

    на prototype собственность не дает никакой информации о теме прототип цепи, но объектов создано теме.

    неудивительно, что название собственности prototype может привести к путанице. Возможно, было бы яснее, если бы это свойство было названо prototypeOfConstructedInstances или что-то в этом роде.

    вы можете прыгать вперед и назад между двумя цепями прототипов:

    Person.prototype.constructor === Person
    

    эта симметрия может быть нарушена путем явного присвоения иной объект prototype собственность (подробнее об этом позже).

    создайте одну функцию, получите два объекта

    Person.prototype - это объект, который был создан одновременно с функцией . Он имеет Person как конструктор, хотя это конструктор фактически еще не выполнен. Таким образом, одновременно создаются два объекта:

    1. функции
    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 на один шаг длиннее, чем p:

    tpPerson.prototypeObject.prototype (конечного пункта)

    другая цепочка прототипов не длиннее:Thief и Person являются ли братья и сестры, разделяющие одного родителя в их прототипе цепи:

    Person}
        Thief } → Function.prototypeObject.prototype (конечного пункта)

    ранее представленная графика может быть расширена до этого (оригинал Thief.prototype остался):

    enter image description here

    синие линии представляют цепочки прототипов, другие цветные линии представляют другие отношения:

    • между объект и его конструктор
    • между конструктором и объектом-прототипом, который будет использоваться для построения объектов

    окончательное руководство по объектно-ориентированному JavaScript - очень краткое и четкое ~30мин видео объяснение заданного вопроса (тема прототипного наследования начинается с 5:45, хотя я бы предпочел послушать все видео). Автор этого видео также сделал JavaScript object visualizer website http://www.objectplayground.com/.enter image description here enter image description here


    Я счел полезным объяснить "цепочку прототипов" как рекурсивное соглашение, когда 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 objects graph

    http://jsobjects.org


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


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

    Prototype похож на модель, на основе которой вы создаете продукт. Важно понимать, что при создании объекта используется другой объект в качестве прототипа, связь между прототипом и продуктом вечна. Например:

    var model = {x:2};
    var product = Object.create(model);
    model.y = 5;
    product.y
    =>5
    

    каждый объект содержит внутреннее свойство, называемое [[prototype]], к которому можно получить доступ с помощью


    рассмотрим следующее снова объект. Я мог бы переписать его так:--21-->

    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 экземпляров теперь используют эти четыре метода вместо каждого иметь собственную копию.


    здесь есть два различных, но связанных объекта, которые нуждаются в объяснении:

    • на .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 s это of the Object функции. Этот прототип содержит прототипический объект, который all [[Prototype]] цепи содержать. На нем определяются все доступные методы для новых объектов:

    // Get properties that are defined on this object
    console.log(Object.getOwnPropertyDescriptors(Object.prototype))
    

    вот так .prototype является объектом, он имеет [[Prototype]] собственность. Когда вы не делаете никаких заданий Function.prototype, the .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)
    

    когда вы do давать задание Function.prototype все, что вы делаете, это расширение цепочки прототипов для включения другого объекта. Это как вставка в отдельный связанный список.

    это в принципе меняет [[Prototype]] цепочка, позволяющая свойства, определенные на объекте, назначенном Function.prototype быть видны объект, созданный функцией.


    [1: это никого не смутит; доступно через the __proto__ свойства во многих реализациях.
    [2]: Все, кроме null.


    еще одна попытка объяснить JavaScript прототип на основе наследования с лучшими фотографиями

    Simple objects inheritanse


    Я всегда люблю аналогии, когда дело доходит до понимания этого типа вещей. "Прототипическое наследование" довольно запутанно по сравнению с наследованием класса bass, на мой взгляд, хотя прототипы намного проще парадигмы. На самом деле с прототипами действительно нет наследования, поэтому имя само по себе вводит в заблуждение, это скорее тип "делегирования".

    представьте себе это ....

    ты в старшей школе, и ты в классе, и у тебя тест, который должен быть сегодня, но у тебя нет ручки, чтобы заполнить ответы. Дох!

    вы сидите рядом с вашим другом Finnius, который может иметь ручку. Вы спрашиваете, и он безуспешно оглядывает свой стол, но вместо того, чтобы сказать: "у меня нет ручки", он хороший друг, он проверяет со своим другом Derp, если у него есть ручка. Баттхерт действительно есть запасная ручка и передает его обратно в Finnius, кто передает ее вам выполнить тест. Баттхерт доверил пера Finnius, кто делегировал пера вам использовать.

    здесь важно то, что Derp не дает вам ручку, так как у вас нет прямого отношения С ним.

    Это упрощенный пример того, как работают прототипы, где дерево данных ищется для того, что вы ищете.


    резюме:

    • функции являются объектами в 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 имеет механизм при поиске свойств объектов, который называется 'прототипным наследованием', вот что в основном тут:

    • сначала проверяется, находится ли свойство на самом объекте. Если это так, это свойство возвращается.
    • если свойство не находится на самом объекте, оно будет "карабкаться вверх по протохейну". Это в основном смотрит на объект, на который ссылается прото собственность. Там он проверяет, доступно ли свойство для объекта, на который ссылается прото
    • если свойство не находится на прото объект, он будет подниматься вверх прото цепь вплоть до объекта 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__, прототип и конструктор отношения: enter image description here