Я не так увлекаюсь динамическими языками программирования, но я написал свою долю кода 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
Также эти слайды очень помогли.
Каждый объект JavaScript имеет внутреннее свойство, называемое [[Prototype]]. Если вы просматриваете свойство через obj.propName
или obj['propName']
, и объект не имеет такого свойства, которое может быть проверено с помощью obj.hasOwnProperty('propName')
- среда выполнения ищет свойство в объекте, на которое ссылается [[Prototype]] вместо, Если у прототипа-объекта также нет такого свойства, его прототип проверяется поочередно, таким образом, ходя по исходной цепочке прототипов объекта, пока не будет найдено совпадение или не будет достигнут его конец.
Некоторые реализации JavaScript допускают прямой доступ к свойству [[Prototype]], например, через нестандартное свойство с именем __proto__
. В общем случае, только возможно установить прототип объекта при создании объекта: если вы создаете новый объект через new Func()
, свойство объекта [[Prototype]] будет установлено в объект, на который ссылается Func.prototype
.
Это позволяет моделировать классы в JavaScript, хотя система наследования JavaScript - как мы видели - прототипная, а не на основе класса:
Подумайте о функциях конструктора как о классах и свойствах прототипа (т.е. объекта, на который ссылается свойство конструктора prototype
), как общих членов, то есть членов, которые одинаковы для каждого экземпляра. В системах на основе классов методы реализуются одинаково для каждого экземпляра, поэтому методы обычно добавляются к прототипу, тогда как поля объектов специфичны для экземпляра и поэтому добавляются к самому объекту во время построения.
В языке, реализующем классическое наследование типа 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();
До сих пор я расширял базовый объект, теперь создаю еще один объект, а затем наследую от Person.
//Create a new object of type Customer by defining its constructor. It 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 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 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() для Person.
//The following statement generates an error.
john.setAmountDue(1000);
Customer.prototype = new Person();
new
оператор действительно требуется здесь? или вы бы намеренно иногда оставляли это? Я думаю, что он все еще будет работать без new
оператора, но изменения в прототипе клиента теперь будут влиять на функциональный объект Person.
Я играю роль учителя JavaScript и концепции прототипа всегда была спорной темой для покрытия, когда я преподаю. Мне потребовалось некоторое время, чтобы придумать хороший способ прояснить концепцию, и теперь в этом тексте я собираюсь объяснить, как работает JavaScript.prototype.
Это очень простая прототипная объектная модель, которая будет рассматриваться как образец во время объяснения, без комментариев:
function Person(name){
this.name = name;
}
Person.prototype.getName = function(){
console.log(this.name);
}
var person = new Person("George");
Есть несколько важных моментов, которые мы должны рассмотреть перед тем, как пройти концепцию прототипа.
Чтобы сделать первый шаг, нам нужно выяснить, как работают функции 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
, который означает, что он привязан к вновь созданному объекту как атрибут с именем __proto__
, поэтому, если мы его изменим, как это было сделано в нашем предыдущем фрагменте кода, все объекты JavaScript будут изменены, а не хорошая практика. Итак, что может быть лучшей практикой сейчас:
person.__proto__ = {
Person: Person,
getName: getName
};
и теперь другие объекты находятся в тишине, но это, по-видимому, не является хорошей практикой. Таким образом, у нас есть еще одно решение, но для использования этого решения мы должны вернуться к той строке кода, где создан объект Person
(var person = {};
), а затем изменить его так:
var propertiesObject = {
Person: Person,
getName: getName
};
var person = Object.create(propertiesObject);
то, что он делает, это создать новый JavaScript Object
и прикрепить propertiesObject
к атрибуту __proto__
. Поэтому, чтобы убедиться, что вы можете сделать:
console.log(person.__proto__===propertiesObject); //true
Но сложной точкой является то, что у вас есть доступ ко всем свойствам, определенным в __proto__
на первом уровне объекта Person
(более подробную информацию см. в итоговой части).
как вы видите, используя любой из этих двух способов this
будет точно указывать на объект Person
.
this
, которая использует call или apply для вызова функции.Метод apply() вызывает функцию с заданным значением и аргументы, предоставленные в виде массива (или подобный массиву объект).
и
Метод call() вызывает функцию с заданным значением и аргументы, предоставленные индивидуально.
таким образом, который является моим любимым, мы можем легко вызвать наши функции, например:
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.
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 = {};
мы имеем 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 FunctionName()
JavaScript внутренне создает объект, пустой хэш, а затем он дает этот объект конструктору, тогда конструктор может делать все, что он хочет, потому что этот внутри этого конструктора является объектом, который был просто и тогда он дает вам этот объект, конечно, если вы не использовали оператор return в своей функции или если вы положили return undefined;
в конец вашего тела функции.
Итак, когда JavaScript переходит на поиск свойства на объекте, первое, что он делает, это он смотрит на этот объект. И тогда существует секретное свойство [[prototype]]
, которое мы обычно имеем как __proto__
, и это свойство выглядит следующим образом. И когда он просматривает __proto__
, поскольку он снова является другим объектом JavaScript, он имеет свой собственный атрибут __proto__
, он поднимается вверх и вверх доходит до точки, где следующий __proto__
имеет значение NULL. Точка является единственным объектом в JavaScript, который имеет атрибут __proto__
: null - это Object.prototype
object:
console.log(Object.prototype.__proto__===null);//true
и что как наследование работает в JavaScript.
Другими словами, когда у вас есть свойство prototype для функции, и вы вызываете новое на этом, после того, как JavaScript закончит просмотр этого вновь созданного объекта для свойств, он перейдет к функции .prototype
, а также возможно, что этот объект имеет свой собственный внутренний прототип. и т.д.
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 сообщества, поэтому люди могут исправить меня, если я ошибаюсь.
prototype
- это свойство функций конструктора, а не экземпляров, т.е. ваш код неверен! Возможно, вы имели в виду нестандартное свойство __proto__
объектов, но это совсем другой зверь ...
Когда Чиро Сан спустился с Горы Огненной Лисы после глубокой медитации, его разум был чист и спокоен.
Однако его рука была беспокойной, и он сам схватил кисть и записал следующие заметки.
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
.
поиск работает (и сколько копий данных сделано). Поэтому я решил понять этот момент. Остальное - Google + посты в блоге + переводчик Js под рукой. :)
После прочтения этой темы, я чувствую себя смущенной с цепочкой прототипов 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.
Каждый объект имеет внутреннее свойство, [[Прототип]], связывая его с другим объектом:
object [[Prototype]] -> anotherObject
В традиционном javascript связанный объект является свойством prototype
функции:
object [[Prototype]] -> aFunction.prototype
Некоторые среды выставляют [[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
не будет использоваться.new
.Эта статья длинна. Но я уверен, что это очистит большинство ваших запросов в отношении "прототипического" характера наследования JavaScript. И даже больше. Пожалуйста, прочитайте полную статью.
JavaScript в основном имеет два типа типов данных
Не объекты
Ниже приведены типы Non object
Эти типы данных возвращаются после использования оператора 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 объекты, которые могут создавать новые объекты с помощью нового оператора, попадают в эту категорию. Например,
Итак, 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))
Цепочка прототипов для различных объектов работает следующим образом.
Для создания объекта без какого-либо прототипа используйте следующее:
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.
Надеюсь, что это поможет.
Javascript не имеет наследования в обычном смысле, но имеет цепочку прототипов.
Если член объекта не может быть найден в объекте, он ищет его в цепочке прототипов. Цепочка состоит из других объектов. Прототип данного экземпляра можно получить с помощью переменной __proto__
. Каждый объект имеет один, поскольку нет разницы между классами и экземплярами в javascript.
Преимущество добавления функции/переменной в прототип заключается в том, что она должна быть в памяти только один раз, а не для каждого экземпляра.
Это также полезно для наследования, потому что цепочка прототипов может состоять из многих других объектов.
Концепция наследования 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
, которое ниже суммирует всю большую диаграмму.
Надеюсь, что это добавит некоторую информацию, я знаю, что этот вид может быть большим, чтобы понять... простыми словами его это просто объекты, связанные с объектами!!!!
Какова цель этого свойства ".prototype"?
Интерфейс со стандартными классами становится расширяемым. Например, вы используете класс Array
, и вам также необходимо добавить собственный сериализатор для всех ваших объектов массива. Вы потратили бы время на кодирование подкласса или использование композиции или... Свойство prototype разрешает это, позволяя пользователям контролировать точный набор членов/методов, доступных для класса.
Подумайте о прототипах в качестве дополнительного vtable-указателя. Когда некоторые члены отсутствуют в исходном классе, прототип просматривается во время выполнения.
Это может помочь классифицировать цепи прототипов в две категории.
Рассмотрим конструктор:
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);
Хотя объект-прототип создается при создании функции-конструктора, вы можете игнорировать этот объект и назначать другой объект, который должен использоваться в качестве прототипа для любых последующих экземпляров, созданных этим конструктором.
Например:
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-минутного вопроса по заданному вопросу (тема Prototypal Inheritance начинается с 5:45, хотя я бы предпочел слушать все видео). Автор этого видео также сделал сайт JavaScript-визуализатора JavaScript 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" может ссылаться на конструктор конструктора program.prototype, а свойства, добавленные в прототип объектов, совместно используются через наследование всеми объектами, совместно использующими прототип.
Позвольте мне рассказать вам свое понимание прототипов. Я не собираюсь сравнивать наследование здесь с другими языками. Я хочу, чтобы люди переставали сравнивать языки и просто понимали язык как сам. Понимание прототипов и прототипного наследования настолько просто, как я покажу вам ниже.
Прототип похож на модель, на основе которой вы создаете продукт. Важным моментом для понимания является то, что при создании объекта с использованием другого объекта в качестве прототипа связь между прототипом и продуктом вечна. Например:
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.
Свойства в продукте обрабатываются следующим образом:
Такое связывание объектов с использованием свойства prototype называется прототипным наследованием. Там, так просто, согласитесь?
Здесь есть два разных, но связанных объекта, которые требуют объяснения:
.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
.
Рассмотрим следующий объект 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 экземпляров теперь используют эти четыре метода, а не каждый из них имеет свою собственную копию.
Еще одна попытка объяснить наследование на основе прототипа JavaScript с лучшими снимками
Мне всегда нравятся аналоги, когда дело доходит до понимания этого типа вещей. "Прототипическое наследование" довольно запутанно по сравнению с наследованием класса баса, на мой взгляд, хотя прототипы - гораздо более простая парадигма. На самом деле с прототипами действительно нет наследования, поэтому само по себе это вводит в заблуждение, это скорее тип делегирования.
Представьте себе это....
Вы в старшей школе, и вы в классе, и у вас есть опрос, которая должна состояться сегодня, но у вас нет ручки, чтобы заполнить ваши ответы. Doh!
Ты сидишь рядом со своим другом Финнисом, у которого может быть ручка. Вы спрашиваете, и он безуспешно оглядывается по столу, но вместо того, чтобы сказать "у меня нет ручки", он хороший друг, которого он проверяет со своим другом другом Дерпом, если у него есть ручка. У Дерпа действительно есть запасное перо и передает его Финниусу, который передает его вам, чтобы завершить викторину. Дерп поручил ручку Finnius, который делегировал вам перо для использования.
Важно то, что Дерп не дает вам ручку, так как у вас нет прямых отношений с ним.
Это упрощенный пример того, как работают прототипы, где дерево данных ищет предмет, который вы ищете.
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 имеет механизм поиска свойств в объектах, который называется "наследование прототипов", вот что он делает в основном:
Например:
function Person(name) {
this.name = name;
}
let mySelf = new Person('Willem');
console.log(mySelf.__proto__ === Person.prototype);
console.log(mySelf.__proto__.__proto__ === Object.prototype);
другая схема, показывающая __proto__, отношения между прототипом и конструктором:
Просто у вас уже есть объект с Object.new
но у вас все еще нет объекта при использовании синтаксиса конструктора.
Важно понимать, что существует различие между прототипом объекта (который доступен через Object.getPrototypeOf(obj)
или через устаревшее свойство obj.__proto__
) и свойством prototype в функциях конструктора. Первый является свойством каждого экземпляра, а второй - свойством конструктора. То есть Object.getPrototypeOf(new Foobar())
ссылается на тот же объект, что и Foobar.prototype
.
Ссылка: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes
Прототип создает новый объект путем клонирования существующего объекта. Так что на самом деле, когда мы думаем о прототипе, мы можем думать о клонировании или создании чего-то, а не о том, чтобы сделать это.