Как работает JavaScript.prototype?
Я не так увлекаюсь динамическими языками программирования, но я написал свою долю кода JavaScript. Я никогда не думал об этом программировании на основе прототипов, кто-нибудь знает, как это работает?
var obj = new Object();
obj.prototype.test = function() { alert('Hello?'); };
var obj2 = new obj();
obj2.test();
Я помню много дискуссий, которые у меня были с людьми некоторое время назад (я не совсем уверен, что я делаю), но, насколько я понимаю, понятия класса не было. Это просто объект, и экземпляры этих объектов являются клонами оригинала, верно?
Но какова точная цель этого свойства.prototype в JavaScript? Как это связано с созданием объектов?
Обновление: правильный путь
var obj = new Object(); // not a functional object
obj.prototype.test = function() { alert('Hello?'); }; // this is wrong!
function MyObject() {} // a first class functional object
MyObject.prototype.test = function() { alert('OK'); } // OK
Также эти слайды очень помогли.
Ответы
Ответ 1
Каждый объект JavaScript имеет внутреннее свойство, называемое [[Prototype]]. Если вы просматриваете свойство через obj.propName
или obj['propName']
, и объект не имеет такого свойства, которое может быть проверено с помощью obj.hasOwnProperty('propName')
- среда выполнения ищет свойство в объекте, на которое ссылается [[Prototype]] вместо, Если у прототипа-объекта также нет такого свойства, его прототип проверяется поочередно, таким образом, ходя по исходной цепочке прототипов объекта, пока не будет найдено совпадение или не будет достигнут его конец.
Некоторые реализации JavaScript допускают прямой доступ к свойству [[Prototype]], например, через нестандартное свойство с именем __proto__
. В общем случае, только возможно установить прототип объекта при создании объекта: если вы создаете новый объект через new Func()
, свойство объекта [[Prototype]] будет установлено в объект, на который ссылается Func.prototype
.
Это позволяет моделировать классы в JavaScript, хотя система наследования JavaScript - как мы видели - прототипная, а не на основе класса:
Подумайте о функциях конструктора как о классах и свойствах прототипа (т.е. объекта, на который ссылается свойство конструктора prototype
), как общих членов, то есть членов, которые одинаковы для каждого экземпляра. В системах на основе классов методы реализуются одинаково для каждого экземпляра, поэтому методы обычно добавляются к прототипу, тогда как поля объектов специфичны для экземпляра и поэтому добавляются к самому объекту во время построения.
Ответ 2
В языке, реализующем классическое наследование типа Java, С# или С++, вы начинаете с создания класса - плана для своих объектов, - и затем вы можете создавать новые объекты из этого класса или вы можете расширить класс, определяя новый класс, который увеличивает исходный класс.
В 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();
Ответ 3
Это очень простая объектная модель на основе прототипа, которая будет рассмотрена в качестве примера при объяснении без комментариев:
function Person(name){
this.name = name;
}
Person.prototype.getName = function(){
console.log(this.name);
}
var person = new Person("George");
Есть несколько важных моментов, которые мы должны рассмотреть, прежде чем перейти к концепции прототипа.
1- Как на самом деле работают функции JavaScript:
Чтобы сделать первый шаг, мы должны выяснить, как на самом деле работают функции JavaScript, как классоподобную функцию, использующую this
ключевое слово или просто как обычную функцию со своими аргументами, что она делает и что возвращает.
Допустим, мы хотим создать объектную модель Person
. но на этом шаге я попытаюсь сделать то же самое без использования prototype
и new
ключевого слова.
Таким образом, на этом этапе functions
, objects
и this
ключевое слово - все, что у нас есть.
Первый вопрос заключается в том, как this
ключевое слово может быть полезным без использования new
ключевого слова.
Итак, чтобы ответить на этот вопрос, скажем, у нас есть пустой объект и две функции, такие как:
var person = {};
function Person(name){ this.name = name; }
function getName(){
console.log(this.name);
}
и теперь без использования new
ключевого слова, как мы могли бы использовать эти функции. Таким образом, у JavaScript есть 3 различных способа сделать это:
а. Первый способ - просто вызвать функцию как обычную функцию:
Person("George");
getName();//would print the "George" in the console
в этом случае это будет текущий объект контекста, который обычно является глобальным объектом window
в браузере или GLOBAL
в Node.js
Это означает, что у нас будет window.name в браузере или GLOBAL.name в Node.js с значением "George".
б. Мы можем прикрепить их к объекту, так как его свойства
- Самый простой способ сделать это - изменить пустой объект person
, например:
person.Person = Person;
person.getName = getName;
таким образом мы можем назвать их как:
person.Person("George");
person.getName();// -->"George"
и теперь объект person
похож на:
Object {Person: function, getName: function, name: "George"}
- Другой способ прикрепить свойство к объекту - использовать prototype
этого объекта, который можно найти в любом объекте JavaScript с именем __proto__
, и я попытался объяснить его немного в итоговой части. Таким образом, мы могли бы получить аналогичный результат, выполнив:
person.__proto__.Person = Person;
person.__proto__.getName = getName;
Но таким образом, что мы на самом деле делаем, это модифицируем Object.prototype
, потому что всякий раз, когда мы создаем объект JavaScript с использованием литералов ({... }
), он создается на основе Object.prototype
, что означает, что он присоединяется к вновь созданному object как атрибут с именем __proto__
, поэтому, если мы изменим его, как мы делали в предыдущем фрагменте кода, все объекты JavaScript будут изменены, что не является хорошей практикой. Итак, что может быть лучше практики сейчас:
person.__proto__ = {
Person: Person,
getName: getName
};
и теперь другие объекты находятся в мире, но это все еще не кажется хорошей практикой. Таким образом, у нас есть еще одно решение, но чтобы использовать это решение, мы должны вернуться к той строке кода, где был создан объект person
(var person = {};
), а затем изменить его следующим образом:
var propertiesObject = {
Person: Person,
getName: getName
};
var person = Object.create(propertiesObject);
он создает новый Object
JavaScript и присоединяет Object
propertiesObject
к __proto__
. Итак, чтобы убедиться, что вы можете сделать:
console.log(person.__proto__===propertiesObject); //true
Но сложность заключается в том, что у вас есть доступ ко всем свойствам, определенным в __proto__
на первом уровне объекта person
(для получения более подробной информации прочитайте итоговую часть).
как вы видите, используя любой из этих двух способов, this
точно указывает на объект person
.
с. У JavaScript есть другой способ предоставить функцию с this
, который использует вызов или применение, чтобы вызвать функцию.
Метод apply() вызывает функцию с заданным значением this и аргументами, представленными в виде массива (или объекта, подобного массиву).
а также
Метод call() вызывает функцию с заданным значением this и аргументами, предоставляемыми индивидуально.
таким образом, который мой любимый, мы можем легко вызывать наши функции как:
Person.call(person, "George");
или же
//apply is more useful when params count is not fixed
Person.apply(person, ["George"]);
getName.call(person);
getName.apply(person);
Эти 3 метода являются важными начальными шагами для выяснения функциональности .prototype.
2- Как работает new
ключевое слово?
это второй шаг для понимания функциональности .prototype
Это то, что я использую для имитации процесса:
function Person(name){ this.name = name; }
my_person_prototype = { getName: function(){ console.log(this.name); } };
в этой части я попытаюсь предпринять все шаги, которые предпринимает JavaScript, без использования new
ключевого слова и prototype
, когда вы используете new
ключевое слово. поэтому, когда мы делаем new Person("George")
, функция Person
служит конструктором. Вот что делает JavaScript один за другим:
а. во-первых, он создает пустой объект, в основном пустой хеш, например:
var newObject = {};
б. следующий шаг, который делает JavaScript, это присоединить все объекты-прототипы к вновь созданному объекту.
у нас есть my_person_prototype
похожий на объект-прототип.
for(var key in my_person_prototype){
newObject[key] = my_person_prototype[key];
}
Это не тот способ, которым JavaScript на самом деле присоединяет свойства, которые определены в прототипе. Фактический путь связан с концепцией цепи прототипов.
а. & б. Вместо этих двух шагов вы можете получить точно такой же результат, выполнив:
var newObject = Object.create(my_person_prototype);
//here you can check out the __proto__ attribute
console.log(newObject.__proto__ === my_person_prototype); //true
//and also check if you have access to your desired properties
console.log(typeof newObject.getName);//"function"
Теперь мы можем вызвать функцию getName
в нашем my_person_prototype
:
newObject.getName();
с. затем он передает этот объект конструктору,
мы можем сделать это с нашим образцом, как:
Person.call(newObject, "George");
или же
Person.apply(newObject, ["George"]);
то конструктор может делать все, что хочет, потому что внутри этого конструктора является объектом, который был только что создан.
теперь конечный результат перед имитацией других шагов: Object {name: "George"}
Резюме:
По сути, когда вы используете ключевое слово new для функции, вы вызываете ее, и эта функция служит конструктором, поэтому, когда вы говорите:
new FunctionName()
JavaScript внутренне делает объект, пустой хэш и затем он дает этот объект в конструктор, то конструктор может делать все, что хочет, потому что внутри этого конструктора объект, который был только что создан, а затем он дает вам этот объект, конечно, если вы не использовали оператор return в своей функции или вы поставили return undefined;
в конце вашей функции тела.
Поэтому, когда JavaScript отправляется на поиск свойства объекта, первое, что он делает, это ищет его на этом объекте. И затем есть секретное свойство [[prototype]]
которое у нас обычно есть, например, __proto__
и это свойство - то, на что JavaScript смотрит дальше. И когда он просматривает __proto__
, поскольку он снова является другим объектом JavaScript, у него есть собственный атрибут __proto__
, он идет вверх и вверх, пока не __proto__
точки, где следующее __proto__
будет нулевым. Точка - единственный объект в JavaScript, у __proto__
атрибут __proto__
равен null, это объект Object.prototype
:
console.log(Object.prototype.__proto__===null);//true
и вот как наследование работает в JavaScript.
Другими словами, когда у вас есть свойство прототипа для функции и вы вызываете новое для него, после того, как JavaScript завершит поиск этого вновь созданного объекта для свойств, он перейдет к функции .prototype
а также возможно, что этот объект имеет свой внутренний прототип. и так далее.
Ответ 4
prototype
позволяет создавать классы. если вы не используете prototype
, тогда он становится статичным.
Вот краткий пример.
var obj = new Object();
obj.test = function() { alert('Hello?'); };
В приведенном выше случае у вас есть статический тест вызова функции. К этой функции можно обращаться только obj.test, где вы можете представить obj как класс.
где, как в приведенном ниже коде
function obj()
{
}
obj.prototype.test = function() { alert('Hello?'); };
var obj2 = new obj();
obj2.test();
Объект стал классом, который теперь может быть создан. Несколько экземпляров obj могут существовать, и все они имеют функцию test
.
Это мое понимание. Я делаю это wiki сообщества, поэтому люди могут исправить меня, если я ошибаюсь.
Ответ 5
Семь Коанов-прототипов
Когда Чиро Сан спустился с Горы Огненной Лисы после глубокой медитации, его разум был чист и спокоен.
Однако его рука была беспокойной, и он сам схватил кисть и записал следующие заметки.
0) Две разные вещи можно назвать "прототипом":
-
свойство prototype, как в obj.prototype
-
внутреннее свойство прототипа, обозначаемое как [[Prototype]]
в ES5.
Его можно получить через ES5 Object.getPrototypeOf()
.
Firefox делает его доступным через свойство __proto__
как расширение. ES6 теперь упоминает некоторые необязательные требования для __proto__
.
1) Эти понятия существуют, чтобы ответить на вопрос:
Когда я делаю obj.property
, где JS ищет .property
?
Интуитивно понятно, что классическое наследование должно влиять на поиск свойств.
2)
-
__proto__
используется для точки .
поиск свойства как в obj.property
. -
.prototype
не используется для поиска напрямую, только косвенно, так как он определяет __proto__
при создании объекта с new
.
Порядок поиска:
- Свойства
obj
добавлены с помощью obj.p =...
или Object.defineProperty(obj,...)
- свойства объекта
obj.__proto__
- свойства объекта
obj.__proto__.__proto__
и т.д. - если какое-то
__proto__
равно null
, вернуть undefined
.
Это так называемая цепь прототипов.
Вы можете избежать .
поиск с помощью obj.hasOwnProperty('key')
и Object.getOwnPropertyNames(f)
3) Есть два основных способа установить obj.__proto__
:
-
new
:
var F = function() {}
var f = new F()
тогда new
установил:
f.__proto__ === F.prototype
Это где .prototype
используется.
-
Object.create
:
f = Object.create(proto)
наборы:
f.__proto__ === proto
4) код:
var F = function() {}
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
Ответ 6
После прочтения этой темы, я чувствую себя смущенной с цепочкой прототипов JavaScript, тогда я нашел эти диаграммы
http://iwiki.readthedocs.org/en/latest/javascript/js_core.html#inheritance
это четкая диаграмма, показывающая наследование JavaScript по прототипной цепочке
и
http://www.javascriptbank.com/javascript/article/JavaScript_Classical_Inheritance/
этот пример содержит пример с кодом и несколькими хорошими диаграммами.
Цепочка прототипа в конечном счете возвращается к Object.prototype.
Цепочка прототипа может быть технически расширена до тех пор, пока вы хотите, каждый раз, устанавливая прототип подкласса, равный объекту родительского класса.
Надеемся, что это также поможет вам понять цепочку прототипов JavaScript.
Ответ 7
Каждый объект имеет внутреннее свойство [[Prototype]], связывающее его с другим объектом:
object [[Prototype]] -> anotherObject
В традиционном javascript связанный объект является свойством prototype
функции:
object [[Prototype]] -> aFunction.prototype
В некоторых средах [[Prototype]] __proto__
как __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;
new
оператор не показывает саму цель ссылки (Object.prototype
); вместо этого цель подразумевается конструктором (Object
).
Помните:
- Каждый объект имеет ссылку, [[Prototype]], иногда
__proto__
как __proto__
. - Каждая функция имеет свойство
prototype
. - Объекты, созданные с помощью
new
, связаны со свойством prototype
их конструктора. - Если функция никогда не используется в качестве конструктора, ее свойство
prototype
останется неиспользованным. - Если вам не нужен конструктор, используйте Object.create вместо
new
.
Ответ 8
Эта статья длинна. Но я уверен, что это очистит большинство ваших запросов
в отношении "прототипического" характера наследования JavaScript. И даже больше. Пожалуйста, прочитайте полную статью.
JavaScript в основном имеет два типа типов данных
Не объекты
Ниже приведены типы Non object
- строка
- число (включая NaN и бесконечность)
- логические значения (true, false)
- undefined
Эти типы данных возвращаются после использования оператора typeof
typeof "строковый литерал" (или переменная, содержащая строковый литерал) === 'строка'
typeof 5 (или любой числовой литерал или переменная, содержащая числовой литерал или NaN или Infynity) === 'number'
typeof true (или false или переменная, содержащая true или false) === 'boolean'
typeof undefined (или переменная undefined или переменная, содержащая undefined) === 'undefined'
Типы данных , число и boolean могут быть представлены как Объекты и Non объекты. Когда они представлены как объекты, их typeof всегда === 'object'. Мы вернемся к этому, когда поняли типы данных объекта.
Объекты
Типы данных объекта можно разделить на два типа
- Объекты типа функций
- Объекты не функционального типа
Объекты типа - это те, которые возвращают строку 'function' с оператором typeof.
Все пользовательские функции и все встроенные JavaScript объекты, которые могут создавать новые объекты с помощью нового оператора, попадают в эту категорию. Например,
- Объект
- Строка
- Номер
- Boolean
- Массив
- Типизированные массивы
- RegExp
- Функция
- Все другие встроенные объекты, которые могут создавать новые объекты с помощью нового оператора
- функция UserDefinedFunction() {/* пользовательский код */}
Итак,
typeof (Object) === typeof (String) === typeof (Number) === typeof (Boolean) === typeof (Array) === typeof (RegExp) === typeof (функция) === typeof (UserDefinedFunction) === 'function'
Все Объекты типа - это фактически экземпляры встроенного объекта JavaScript Функция (включая объект Функция, то есть он рекурсивно определен), Это как если бы эти объекты были определены следующим образом.
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")
Как уже упоминалось, объекты Тип функции могут создавать новые объекты с помощью оператора new. Например, для объекта типа Объект, Строка, Число, Логическое, Массив, 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()
Созданные объекты - это все Объекты типа Non Function и возвращают тип === 'объект. Во всех этих случаях объект "a" не может далее создавать
объекты с использованием оператора new. Итак, неправильно:
var b=new a() //error. a is not typeof==='function'
Встроенный объект Math - typeof === 'object'. Следовательно, новый объект типа Math не может быть создан новым оператором.
var b=new Math() //error. Math is not typeof==='function'
Также обратите внимание, что Объект, Массив и 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.
Так как объекты Объекты функций могут создавать новые объекты, их также называют Конструкторами.
Каждый Конструктор/Функция(независимо от того, была ли построена или определена пользователем), когда определено автоматически, имеет свойство "prototype", значение которого по умолчанию задано как объект. Этот объект имеет свойство "конструктор, который по умолчанию ссылается на Конструктор/Функция.
Например, когда мы определяем функцию
function UserDefinedFunction()
{
}
автоматически происходит
UserDefinedFunction.prototype={constructor:UserDefinedFunction}
Это свойство "prototype" присутствует только в объектах типа функций
(и никогда не в объектах типа Non Function).
Это связано с тем, что при создании нового объекта (с использованием нового оператора) он наследует все свойства и методы из объекта прототипа функции конструктора, т.е. внутренняя ссылка создается во вновь созданном объекте, который ссылается на объект, на который ссылается объект прототипа функции Constructor.
Эта "внутренняя ссылка, созданная в объекте для ссылки на унаследованные свойства, известна как прототип объекта (который ссылается на объект, на который ссылается конструктор "prototype", но отличается от него). Для любого объекта (Function или Non Function) это можно получить с помощью метода Object.getPrototypeOf(). Используя этот метод, можно проследить цепочку прототипов объекта.
Кроме того, каждый созданный объект (Тип функции или Тип нефункции) имеет конструктор ", которое наследуется от объекта, на который ссылается свойство prototype функции Constructor. По умолчанию свойство " конструктор ссылается на конструктор, который его создал (если <конструктоp > по умолчанию "prototype" не изменен).
Для всех объектов типа функций функция конструктора всегда
Функция Function() {}
Для объектов типа Non Function (например, Javascript Built in Math object) функция-конструктор - это функция, которая ее создала.
Для объекта Math это функция Object() {}.
Вся описанная выше концепция может быть немного сложной для понимания без какого-либо вспомогательного кода. Прочтите следующий код, чтобы понять концепцию. Попробуйте выполнить его, чтобы лучше понять.
function UserDefinedFunction()
{
}
/* creating the above function automatically does the following as mentioned earlier
UserDefinedFunction.prototype={constructor:UserDefinedFunction}
*/
var newObj_1=new UserDefinedFunction()
alert(Object.getPrototypeOf(newObj_1)===UserDefinedFunction.prototype) //Displays true
alert(newObj_1.constructor) //Displays function UserDefinedFunction
//Create a new property in UserDefinedFunction.prototype object
UserDefinedFunction.prototype.TestProperty="test"
alert(newObj_1.TestProperty) //Displays "test"
alert(Object.getPrototypeOf(newObj_1).TestProperty)// Displays "test"
//Create a new Object
var objA = {
property1 : "Property1",
constructor:Array
}
//assign a new object to UserDefinedFunction.prototype
UserDefinedFunction.prototype=objA
alert(Object.getPrototypeOf(newObj_1)===UserDefinedFunction.prototype) //Displays false. The object referenced by UserDefinedFunction.prototype has changed
//The internal reference does not change
alert(newObj_1.constructor) // This shall still Display function UserDefinedFunction
alert(newObj_1.TestProperty) //This shall still Display "test"
alert(Object.getPrototypeOf(newObj_1).TestProperty) //This shall still Display "test"
//Create another object of type UserDefinedFunction
var newObj_2= new UserDefinedFunction();
alert(Object.getPrototypeOf(newObj_2)===objA) //Displays true.
alert(newObj_2.constructor) //Displays function Array()
alert(newObj_2.property1) //Displays "Property1"
alert(Object.getPrototypeOf(newObj_2).property1) //Displays "Property1"
//Create a new property in objA
objA.property2="property2"
alert(objA.property2) //Displays "Property2"
alert(UserDefinedFunction.prototype.property2) //Displays "Property2"
alert(newObj_2.property2) // Displays Property2
alert(Object.getPrototypeOf(newObj_2).property2) //Displays "Property2"
Цепочка прототипов каждого объекта в конечном счете возвращается к объекту Object.prototype(который сам по себе не имеет прототипа).
Следующий код может использоваться для отслеживания цепочки прототипов объекта
var o=Starting object;
do {
alert(o + "\n" + Object.getOwnPropertyNames(o))
}while(o=Object.getPrototypeOf(o))
Цепочка прототипов для различных объектов работает следующим образом.
- Каждый объект Function (включая встроенный объект Function) → Function.prototype → Object.prototype → null
- Простые объекты (созданные новым объектом() или {}, включая встроенный объект Math) → Object.prototype → null
- Объект, созданный с помощью новой или Object.create → Цепочки прототипов One или More → Object.prototype → null
Для создания объекта без какого-либо прототипа используйте следующее:
var o=Object.create(null)
alert(Object.getPrototypeOf(o)) //Displays null
Можно подумать, что установка свойства prototype конструктора в null должна создать объект с нулевым прототипом. Однако в таких случаях созданный прототип объекта устанавливается в Object.prototype, и его конструктор настроен на функцию Object. Об этом свидетельствует следующий код
function UserDefinedFunction(){}
UserDefinedFunction.prototype=null// Can be set to any non object value (number,string,undefined etc.)
var o=new UserDefinedFunction()
alert(Object.getPrototypeOf(o)==Object.prototype) //Displays true
alert(o.constructor) //Displays Function Object
Следуя в резюме этой статьи
- Существует два типа объектов Типы функций и Нефункциональные типы
-
Только Объекты типа функций могут создавать новый объект с помощью оператора new. Созданные объекты представляют собой объекты Non Function type. Объекты Non Function type не могут создавать объект с помощью оператора new.
-
Все Объекты типа функций по умолчанию имеют свойство "prototype". Это свойство "prototype" ссылается на объект с конструктором "конструктор, который по умолчанию ссылается на объект Тип объекта.
-
Все объекты (Тип функции и Тип нефункции) имеют свойство "конструктор", которое по умолчанию ссылается на созданный им объект Объект функции/ Конструктор.
-
Каждый объект, который создается внутри, ссылается на объект, на который ссылается
"prototype" свойства создателя, создавшего его. Этот объект известен как созданный прототип объекта (который отличается от свойства объектов типа "prototype", который он ссылается). Таким образом, созданный объект может напрямую обращаться к методам и свойствам, определенным в объекте, на который ссылается свойство Constructor "prototype" (во время создания объекта).
-
Прототип объекта (и, следовательно, его наследуемые имена свойств) можно получить с помощью метода Object.getPrototypeOf(). На самом деле этот метод
может использоваться для навигации по всей цепочке прототипов объекта.
-
Цепочка прототипов каждого объекта в конечном счете возвращается к Object.prototype(если объект не создан с использованием Object.create(null), и в этом случае у объекта нет прототипа).
-
typeof (new Array()) === 'object' - это дизайн языка, а не ошибка, указанная Дуглас Крокфорд
-
Установка свойства prototype конструктора в null (или undefined, number, true, false, string) не должна создавать объект с нулевым прототипом. В таких случаях созданный прототип объекта устанавливается в Object.prototype, а его конструктор настроен на функцию Object.
Надеюсь, что это поможет.
Ответ 9
Javascript не имеет наследования в обычном смысле, но имеет цепочку прототипов.
цепочка прототипов
Если член объекта не может быть найден в объекте, он ищет его в цепочке прототипов. Цепочка состоит из других объектов. Прототип данного экземпляра можно получить с помощью переменной __proto__
. Каждый объект имеет один, поскольку нет разницы между классами и экземплярами в javascript.
Преимущество добавления функции/переменной в прототип заключается в том, что она должна быть в памяти только один раз, а не для каждого экземпляра.
Это также полезно для наследования, потому что цепочка прототипов может состоять из многих других объектов.
Ответ 10
Концепция наследования prototypal
является одним из самых сложных для многих разработчиков. Попробуем понять корень проблемы, чтобы лучше понять prototypal inheritance
. Начнем с функции plain
.
Если мы используем оператор new
на Tree function
, мы называем его как функцию constructor
.
Каждая функция JavaScript
имеет a prototype
. Когда вы регистрируете Tree.prototype
, вы получаете...
Если вы посмотрите на вышеприведенный вывод console.log()
, вы можете увидеть свойство конструктора в свойствах Tree.prototype
и __proto__
. __proto__
представляет prototype
, что этот function
основан на выключении, и поскольку это всего лишь простой JavaScript function
без inheritance
, установленный еще, он ссылается на Object prototype
, который только что встроен в к JavaScript...
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype
Это имеет такие вещи, как .toString, .toValue, .hasOwnProperty
и т.д.
__proto__
, который был принесен моей мозилле, устарел и заменен на метод Object.getPrototypeOf
, чтобы получить Object prototype
.
Object.getPrototypeOf(Tree.prototype); // Object {}
Добавьте метод к нашему Tree
prototype
.
Мы модифицировали Root
и добавили к нему ветвь function
.
Это означает, что при создании instance
Tree
вы можете вызвать метод branch
.
Мы также можем добавить primitives
или objects
в наш prototype
.
Допустим a child-tree
к нашему Tree
.
Здесь Child
наследует свой prototype
от дерева, то, что мы здесь делаем, использует метод Object.create()
для создания нового объекта, основанного на том, что вы проходите, здесь это Tree.prototype
. В этом случае мы создаем прототип Child для нового объекта, который выглядит как прототип Tree
. Затем мы устанавливаем Child constructor to Child
, если мы не будем указывать на Tree()
.
Child
теперь имеет свой собственный prototype
, его __proto__
указывает на Tree
и Tree prototype
указывает на base Object
.
Child
|
\
\
Tree.prototype
- branch
|
|
\
\
Object.prototype
-toString
-valueOf
-etc., etc.
Теперь вы создаете instance
из Child
и вызываете branch
, который изначально доступен в Tree
. Мы фактически не определили наш branch
на Child prototype
. НО, в Root prototype
, из которого ребенок наследует.
В JS все не является объектом, все может действовать как объект.
JavaScript
имеет такие примитивы, как strings, number, booleans, undefined, null.
Они не object(i.e reference types)
, но, безусловно, могут действовать как Object
. Рассмотрим здесь пример.
В первой строке этого списка для имени присваивается строковое значение primitive
. Вторая строка относится к имени типа Object
и вызывает charAt(0)
с использованием точечной нотации.
Вот что происходит за кулисами:
// что движок JavaScript
делает
String object
существует только для одного оператора перед его уничтожением (процесс называется autoboxing
). Вернемся к нашему prototypal
inheritance
.
-
JavaScript
поддерживает наследование через delegation
на основе
prototypes
.
- Каждый
function
имеет свойство prototype
, которое ссылается на другое
объект.
-
properties/functions
выглядят из самого Object
или через
prototype
цепочка, если она не существует
A prototype
в JS - это объект, который yields
вам принадлежит родительскому элементу другого Object
. [то есть делегирование] delegation
означает, что если вы не можете что-то сделать, вы скажете кому-то еще сделать это за вас.
https://jsfiddle.net/say0tzpL/1/
Если вы посмотрите вышеприведенную скрипту, у собаки есть доступ к методу toString
, но она недоступна в ней, но доступна через цепочку прототипов, которая делегирует Object.prototype
Если вы посмотрите на приведенный ниже, мы пытаемся получить доступ к методу call
, который доступен в каждом function
.
https://jsfiddle.net/rknffckc/
Если вы посмотрите на приведенную выше скрипту, Profile
Функция имеет доступ к методу call
, но ее недоступна в ней, но доступна через цепочку прототипов, которая делегирует Function.prototype
Примечание. prototype
является свойством конструктора функций, тогда как __proto__
является свойством объектов, построенных из конструктора функций. Каждая функция имеет свойство prototype
, значение которой является пустым Object
. Когда мы создаем экземпляр функции, мы получаем внутреннее свойство [[Prototype]]
или __proto__
, чья ссылка является прототипом функции constructor
.
Вышеприведенная диаграмма выглядит немного сложной, но выводит всю картину о том, как работает prototype chaining
. Продвигайтесь медленно:
Есть два экземпляра b1
и b2
, конструктор которого Bar
, а parent - Foo и имеет два метода из цепочки прототипов identify
и speak
через Bar
и Foo
https://jsfiddle.net/kbp7jr7n/
Если вы посмотрите на код выше, у нас есть конструктор Foo
, у которого есть метод identify()
и Bar
, у которого есть метод speak
. Мы создаем два экземпляра Bar
b1
и b2
, родительский тип которых Foo
. Теперь, вызывая метод speak
Bar
, мы можем определить, кто вызывает разговор через цепочку prototype
.
Bar
теперь имеет все методы Foo
, которые определены в его prototype
. Давайте еще больше углубимся в понимание Object.prototype
и Function.prototype
и то, как они связаны. Если вы посмотрите на конструктор Foo
, Bar
и Object
- Function constructor
.
prototype
Bar
составляет Foo
, prototype
of Foo
is Object
, и если вы внимательно посмотрите, prototype
of Foo
связан с Object.prototype
.
Прежде чем закрыть это, давайте просто оберните небольшим фрагментом кода здесь, чтобы суммировать все выше. Мы используем оператор instanceof
здесь, чтобы проверить, имеет ли Object
в своей цепочке prototype
свойство prototype
a constructor
, которое ниже суммирует всю большую диаграмму.
Надеюсь, что это добавит некоторую информацию, я знаю, что этот вид может быть большим, чтобы понять... простыми словами его это просто объекты, связанные с объектами!!!!
Ответ 11
Какова цель этого свойства ".prototype"?
Интерфейс со стандартными классами становится расширяемым. Например, вы используете класс Array
, и вам также необходимо добавить собственный сериализатор для всех ваших объектов массива. Вы потратили бы время на кодирование подкласса или использование композиции или... Свойство prototype разрешает это, позволяя пользователям контролировать точный набор членов/методов, доступных для класса.
Подумайте о прототипах в качестве дополнительного vtable-указателя. Когда некоторые члены отсутствуют в исходном классе, прототип просматривается во время выполнения.
Ответ 12
Это может помочь классифицировать цепи прототипов в две категории.
Рассмотрим конструктор:
function Person() {}
Значение Object.getPrototypeOf(Person)
является функцией. На самом деле это Function.prototype
. Поскольку Person
был создан как функция, он разделяет тот же объект-объект прототипа, что и все функции. Это то же самое, что и Person.__proto__
, но это свойство не должно использоваться. Во всяком случае, при Object.getPrototypeOf(Person)
вы эффективно поднимаетесь по лестнице так называемой цепи прототипов.
Цепочка в направлении вверх выглядит следующим образом:
Person
→ Function.prototype
→ Object.prototype
(конечная точка)
Важно то, что эта цепочка прототипов имеет мало общего с объектами, которые может быть сконструирован Person
. Эти построенные объекты имеют свою собственную прототипную цепочку, и эта цепочка потенциально не может иметь близкого предшественника с упомянутым выше.
Возьмем, к примеру, этот объект:
var p = new Person();
p не имеет прямых отношений между прототипом и линией. Их отношения разные. Объект p имеет свою собственную прототипную цепочку. Используя Object.getPrototypeOf
, вы найдете цепочку следующим образом:
p
→ Person.prototype
→ Object.prototype
(конечная точка)
В этой цепочке нет функционального объекта (хотя это может быть).
Итак, Person
кажется связанным с двумя типами цепей, которые живут своей жизнью. Чтобы "прыгать" из одной цепи в другую, вы используете:
-
.prototype
: перейти от цепочки конструктора к цепочке созданных объектов. Это свойство, таким образом, определяется только для объектов функции (поскольку new
может использоваться только для функций).
-
.constructor
: перейти от цепочки созданных объектов к цепочке конструкторов.
Здесь представлено визуальное представление двух задействованных цепочек прототипов, представленных в виде столбцов:
Подводя итог:
Свойство prototype
не дает информации о цепочке прототипов субъекта, а о объектах, созданных субъектом.
Неудивительно, что имя свойства prototype
может привести к путанице. Возможно, было бы яснее, если это свойство было названо prototypeOfConstructedInstances
или что-то в этом направлении.
Вы можете прыгать назад и вперед между двумя цепочками прототипов:
Person.prototype.constructor === Person
Эта симметрия может быть разбита путем явного назначения другого объекта свойству prototype
(подробнее об этом позже).
Создать одну функцию, получить два объекта
Person.prototype
- это объект, который был создан одновременно с созданием функции Person
. Он имеет конструкцию Person
, хотя этот конструктор еще не выполнялся. Таким образом, одновременно создаются два объекта:
- Сама функция
Person
- Объект, который будет действовать как прототип, когда функция вызывается как конструктор
Оба являются объектами, но они имеют разные роли: объект объекта строит, а другой объект представляет собой прототип любого объекта, который будет строить функция. Объект-прототип станет родителем построенного объекта в цепочке прототипов.
Так как функция также является объектом, она также имеет свой собственный родитель в своей собственной цепочке прототипов, но помните, что эти две цепи имеют разные вещи.
Вот некоторые равенства, которые могут помочь понять проблему - все эти print 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);
Ответ 13
Окончательное руководство по объектно-ориентированному JavaScript - очень краткое и понятное объяснение 30-минутного вопроса по заданному вопросу (тема Prototypal Inheritance начинается с 5:45, хотя я бы предпочел слушать все видео). Автор этого видео также сделал сайт JavaScript-визуализатора JavaScript http://www.objectplayground.com/.
Ответ 14
Мне было полезно объяснить "цепочку прототипов" как рекурсивное соглашение, когда ссылается 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 от их свойств здесь:
http://jsobjects.org
Ответ 15
Когда конструктор создает объект, этот объект неявно ссылается на свойство конструкторов "prototype" с целью разрешения ссылок на свойства. Свойство конструкторов "prototype" может ссылаться на конструктор конструктора program.prototype, а свойства, добавленные в прототип объектов, совместно используются через наследование всеми объектами, совместно использующими прототип.
Ответ 16
Позвольте мне рассказать вам свое понимание прототипов. Я не собираюсь сравнивать наследование здесь с другими языками. Я хочу, чтобы люди переставали сравнивать языки и просто понимали язык как сам. Понимание прототипов и прототипного наследования настолько просто, как я покажу вам ниже.
Прототип похож на модель, на основе которой вы создаете продукт. Важным моментом для понимания является то, что при создании объекта с использованием другого объекта в качестве прототипа связь между прототипом и продуктом вечна. Например:
var model = {x:2};
var product = Object.create(model);
model.y = 5;
product.y
=>5
Каждый объект содержит внутреннее свойство, называемое [[прототипом]], к которому можно получить доступ с помощью функции Object.getPrototypeOf()
. Object.create(model)
создает новый объект и присваивает ему свойство [[prototype]] для объекта модели. Следовательно, когда вы делаете Object.getPrototypeOf(product)
, вы получите объект model.
Свойства в продукте обрабатываются следующим образом:
- Когда доступ к объекту доступен только для чтения, он просматривается в цепочке областей видимости. Поиск переменной начинается с продукта вверх до прототипа. Если такая переменная найдена в поиске, поиск останавливается прямо там, и значение возвращается. Если такая переменная не может быть найдена в цепочке областей видимости, возвращается undefined.
- Когда свойство записывается (изменяется), свойство всегда записывается в объект product. Если продукт уже не имеет такого свойства, он неявно создается и записывается.
Такое связывание объектов с использованием свойства prototype называется прототипным наследованием. Там, так просто, согласитесь?
Ответ 17
Здесь есть две разные, но взаимосвязанные сущности, которые нужно объяснить
- Свойство
.prototype
функций. - Свойство
[[Prototype]]
[1] всех объектов [2].
Это две разные вещи.
Свойство [[Prototype]]
:
Это свойство, которое существует на всех [2] объектах.
Здесь хранится другой объект, который, как сам объект, имеет собственный [[Prototype]]
который указывает на другой объект. Этот другой объект имеет собственный [[Prototype]]
. Эта история продолжается до тех пор, пока вы не достигнете прототипа объекта, который предоставляет методы, доступные для всех объектов (например, .toString
).
Свойство [[Prototype]]
является частью того, что образует цепочку [[Prototype]]
. Эта цепочка объектов [[Prototype]]
проверяется, например, когда над объектом выполняются операции [[Get]]
или [[Set]]
:
var obj = {}
obj.a // [[Get]] consults prototype chain
obj.b = 20 // [[Set]] consults prototype chain
Свойство .prototype
:
Это свойство, которое можно найти только в функциях. Используя очень простую функцию:
function Bar(){};
Свойство .prototype
содержит объект, который будет присвоен b.[[Prototype]]
когда вы делаете var b = new Bar
. Вы можете легко проверить это:
// Both assign Bar.prototype to b1/b2[[Prototype]]
var b = new Bar;
// Object.getPrototypeOf grabs the objects [[Prototype]]
console.log(Object.getPrototypeOf(b) === Bar.prototype) // true
Один из наиболее важных .prototype
- это функция Object
. Этот прототип содержит прототип объекта, который содержится во всех цепочках [[Prototype]]
. На нем определены все доступные методы для новых объектов:
// Get properties that are defined on this object
console.log(Object.getOwnPropertyDescriptors(Object.prototype))
Теперь, так как .prototype
является объектом, он имеет свойство [[Prototype]]
. Когда вы не делаете никаких назначений для Function.prototype
, .prototype
[[Prototype]]
указывает на прототипный объект (Object.prototype
). Это автоматически выполняется каждый раз, когда вы создаете новую функцию.
Таким образом, каждый раз, когда вы делаете new Bar;
цепочка прототипов настроена для вас, вы получаете все, что определено в Bar.prototype
и все, что определено в Object.prototype
:
var b = new Bar;
// Get all Bar.prototype properties
console.log(b.__proto__ === Bar.prototype)
// Get all Object.prototype properties
console.log(b.__proto__.__proto__ === Object.prototype)
Когда вы делаете назначения для Function.prototype
все, что вы делаете, это расширяете цепочку прототипов, чтобы включить в нее другой объект. Это как вставка в односвязный список.
Это в основном изменяет цепочку [[Prototype]]
позволяя свойствам, определенным для объекта, назначенного для Function.prototype
быть видимым любым объектом, созданным функцией.
[1: Это никого не смущает;доступно через свойство __proto__
во многих реализациях.
[2]: все, кроме null
.
Ответ 18
Рассмотрим следующий объект keyValueStore
:
var keyValueStore = (function() {
var count = 0;
var kvs = function() {
count++;
this.data = {};
this.get = function(key) { return this.data[key]; };
this.set = function(key, value) { this.data[key] = value; };
this.delete = function(key) { delete this.data[key]; };
this.getLength = function() {
var l = 0;
for (p in this.data) l++;
return l;
}
};
return { // Singleton public properties
'create' : function() { return new kvs(); },
'count' : function() { return count; }
};
})();
Я могу создать новый экземпляр этого объекта, выполнив следующее:
kvs = keyValueStore.create();
Каждый экземпляр этого объекта имеет следующие общедоступные свойства:
-
data
-
get
-
set
-
delete
-
getLength
Теперь предположим, что мы создаем 100 экземпляров этого объекта keyValueStore
. Даже если get
, set
, delete
, getLength
будут делать то же самое для каждого из этих 100 экземпляров, каждый экземпляр имеет свою собственную копию этой функции.
Теперь представьте, можете ли вы иметь только одну копию get
, set
, delete
и getLength
, и каждый экземпляр ссылается на эту же функцию. Это будет лучше для производительности и потребует меньше памяти.
То, что происходит в прототипах. Прототип - это "схема" свойств, которые наследуются, но не копируются экземплярами. Таким образом, это означает, что он существует только один раз в памяти для всех экземпляров объекта и разделяется всеми этими экземплярами.
Теперь рассмотрим объект keyValueStore
еще раз. Я мог бы переписать его вот так:
var keyValueStore = (function() {
var count = 0;
var kvs = function() {
count++;
this.data = {};
};
kvs.prototype = {
'get' : function(key) { return this.data[key]; },
'set' : function(key, value) { this.data[key] = value; },
'delete' : function(key) { delete this.data[key]; },
'getLength' : function() {
var l = 0;
for (p in this.data) l++;
return l;
}
};
return {
'create' : function() { return new kvs(); },
'count' : function() { return count; }
};
})();
Это ТОЧНО аналогично предыдущей версии объекта keyValueStore
, за исключением того, что все его методы теперь помещены в прототип. Это означает, что все 100 экземпляров теперь используют эти четыре метода, а не каждый из них имеет свою собственную копию.
Ответ 19
Еще одна попытка объяснить наследование на основе прототипа JavaScript с лучшими снимками
Ответ 20
Мне всегда нравятся аналоги, когда дело доходит до понимания этого типа вещей. "Прототипическое наследование" довольно запутанно по сравнению с наследованием класса баса, на мой взгляд, хотя прототипы - гораздо более простая парадигма. На самом деле с прототипами действительно нет наследования, поэтому само по себе это вводит в заблуждение, это скорее тип делегирования.
Представьте себе это....
Вы в старшей школе, и вы в классе, и у вас есть опрос, которая должна состояться сегодня, но у вас нет ручки, чтобы заполнить ваши ответы. Doh!
Ты сидишь рядом со своим другом Финнисом, у которого может быть ручка. Вы спрашиваете, и он безуспешно оглядывается по столу, но вместо того, чтобы сказать "у меня нет ручки", он хороший друг, которого он проверяет со своим другом другом Дерпом, если у него есть ручка. У Дерпа действительно есть запасное перо и передает его Финниусу, который передает его вам, чтобы завершить викторину. Дерп поручил ручку Finnius, который делегировал вам перо для использования.
Важно то, что Дерп не дает вам ручку, так как у вас нет прямых отношений с ним.
Это упрощенный пример того, как работают прототипы, где дерево данных ищет предмет, который вы ищете.
Ответ 21
Резюме:
- Функции являются объектами в 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.
Ответ 22
другая схема, показывающая __proto__, отношения между прототипом и конструктором:
Ответ 23
Просто у вас уже есть объект с Object.new
но у вас все еще нет объекта при использовании синтаксиса конструктора.
Ответ 24
Прототип создает новый объект путем клонирования существующего объекта. Так что на самом деле, когда мы думаем о прототипе, мы можем думать о клонировании или создании чего-то, а не о том, чтобы сделать это.
Ответ 25
Важно понимать, что существует различие между прототипом объекта (который доступен через Object.getPrototypeOf(obj)
или через устаревшее свойство __proto__
) и свойством prototype
в функциях конструктора. Первый является свойством каждого экземпляра, а второй - свойством конструктора. То есть Object.getPrototypeOf(new Foobar())
ссылается на тот же объект, что и Foobar.prototype
.
Ссылка: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes