Как на 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
это четкая диаграмма, чтобы показать наследование 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__
isnull
, returnundefined
.
это так называемый прототип цепи.
вы можете избежать .
поиск с 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'. Мы вернемся к этому, как только поймем типы данных объекта.
объекты
типы данных объекта можно разделить на два типа
- функции объекты типа
- объекты не функционального типа
на функции объекты типа это те, которые возвращают строку '' С 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
, вы получаете...
если вы посмотрите на выше 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
.
Object.getPrototypeOf(Tree.prototype); // Object {}
давайте добавим метод к нашему Tree
prototype
.
мы изменили Root
и добавил function
филиала к нему.
это означает, когда вы создаете instance
of Tree
вы можете называть это branch
метод.
мы также можем добавить primitives
или objects
нашим Prototype
.
добавьте child-tree
нашим Tree
.
здесь Child
наследует prototype
из дерева, то, что мы делаем здесь, использует Object.create()
метод создания нового объекта на основе того, что вы передаете, вот он Tree.prototype
. В этом случае мы устанавливаем прототип дочернего объекта на новый объект, который выглядит идентично Tree
прототип. Далее мы устанавливаем Child's constructor to Child
, если мы не он бы Tree()
.
Child
теперь имеет свой собственный prototype
, его __proto__
указывает на Tree
и Tree's prototype
указывает на основания Object
.
Child
|
\
\
Tree.prototype
- branch
|
|
\
\
Object.prototype
-toString
-valueOf
-etc., etc.
теперь вы создаете instance
of Child
и звонок branch
который первоначально доступен в Tree
. Мы на самом деле не определили наш branch
на Child prototype
. Но, в Root prototype
от которого ребенок наследует.
в JS все не является объектом, все может действовать как объект.
Javascript
есть примитивы типа strings, number, booleans, undefined, null.
их нет object(i.e reference types)
, но, конечно, может действовать как object
. Давайте рассмотрим пример здесь.
в первой строке этого списка a primitive
строковое значение присваивается name. Вторая строка лечит имя как object
и звонки charAt(0)
использование точечной нотации.
вот что происходит за кулисами: // что за
какова точная цель этого ".прототип " собственности?
интерфейс к стандартным классам становится расширяемым. Например, вы используете Array
class, и Вам также нужно добавить пользовательский сериализатор для всех ваших объектов массива. Потратите ли вы время на кодирование подкласса или используйте композицию или ... Свойство prototype решает эту проблему, позволяя пользователям контролировать точный набор членов/методов класса.
думать прототипы как дополнительный vtable-указатель. Когда некоторые члены отсутствуют в исходном классе, прототип просматривается во время выполнения.
это может помочь классифицировать цепи прототипов на две категории.
считайте конструктор:
function Person() {}
значение Object.getPrototypeOf(Person)
- это функция. На самом деле, это Function.prototype
. С Person
был создан как функция, он разделяет тот же объект функции прототипа, что и все функции. Это то же самое, что Person.__proto__
, но это свойство не должно использоваться. Во всяком случае, с Object.getPrototypeOf(Person)
вы эффективно поднимаетесь по лестнице того, что называется прототипом цепь.
цепь в направлении вверх выглядит так:
Person
→ Function.prototype
→ Object.prototype
(конечного пункта)
важно то, что эта цепь-прототип имеет мало общего с объектами, которые Person
can построить. Эти сконструированные объекты имеют свою собственную цепочку прототипов,и эта цепочка потенциально не может иметь близкого общего предка с вышеупомянутым.
возьмите, например, это объект:
var p = new Person();
p не имеет прямого отношения прототипа-цепи с человек. У них другие отношения. Объект p имеет свою собственную цепочку прототипов. Используя Object.getPrototypeOf
, вы найдете цепь следующим образом:
p
→ Person.prototype
→ Object.prototype
(конечного пункта)
в этой цепочке нет объекта функции (хотя это может быть).
так Person
кажется, связано с двумя видами цепей, которые живут своей жизнью. Чтобы "перепрыгнуть" с одной цепи на другую, вы используете:
.prototype
: переход от цепочки конструктора к цепочке созданного объекта. Таким образом, это свойство определяется только для объектов функций (asnew
можно использовать только в функциях)..constructor
: переход от цепочки созданного объекта к цепочке конструктора.
вот визуальное представление двух задействованы прототипы цепочек, представленные в виде столбцов:
в итоге:
на
prototype
собственность не дает никакой информации о теме прототип цепи, но объектов создано теме.
неудивительно, что название собственности prototype
может привести к путанице. Возможно, было бы яснее, если бы это свойство было названо prototypeOfConstructedInstances
или что-то в этом роде.
вы можете прыгать вперед и назад между двумя цепями прототипов:
Person.prototype.constructor === Person
эта симметрия может быть нарушена путем явного присвоения иной объект prototype
собственность (подробнее об этом позже).
создайте одну функцию, получите два объекта
Person.prototype
- это объект, который был создан одновременно с функцией . Он имеет Person
как конструктор, хотя это конструктор фактически еще не выполнен. Таким образом, одновременно создаются два объекта:
- функции
- объект, который будет действовать как прототип, когда функция вызывается как конструктор
оба являются объектами, но они имеют разные функции: функцию объекта конструкции, в то время как другой объект представляет собой прототип любого объекта, который будет сконструирован функцией. Прототипом объекта станет родитель построенного объекта в цепочке прототипов.
поскольку функция также является объектом, она также имеет своего родителя в своей собственной цепи прототипов, но помните, что эти две цепи о разных вещах.
вот некоторые равенства, которые могли бы помочь понять проблему - все эти печати 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:
t
→ p
→ Person.prototype
→ Object.prototype
(конечного пункта)
другая цепочка прототипов не длиннее:Thief
и Person
являются ли братья и сестры, разделяющие одного родителя в их прототипе цепи:
Person
}
Thief
} → Function.prototype
→ Object.prototype
(конечного пункта)
ранее представленная графика может быть расширена до этого (оригинал Thief.prototype
остался):
синие линии представляют цепочки прототипов, другие цветные линии представляют другие отношения:
- между объект и его конструктор
- между конструктором и объектом-прототипом, который будет использоваться для построения объектов
окончательное руководство по объектно-ориентированному JavaScript - очень краткое и четкое ~30мин видео объяснение заданного вопроса (тема прототипного наследования начинается с 5:45, хотя я бы предпочел послушать все видео). Автор этого видео также сделал JavaScript object visualizer website http://www.objectplayground.com/.
Я счел полезным объяснить "цепочку прототипов" как рекурсивное соглашение, когда 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 по их свойствам здесь:
когда конструктор создает объект, этот объект неявно ссылается на свойство "прототип" конструктора с целью разрешения ссылок на свойства. На свойство "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 прототип на основе наследования с лучшими фотографиями
Я всегда люблю аналогии, когда дело доходит до понимания этого типа вещей. "Прототипическое наследование" довольно запутанно по сравнению с наследованием класса 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);
просто у вас уже есть объект с объектом.новый, но у вас все еще нет объекта при использовании синтаксиса конструктора.