Как работает 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

Также эти слайды очень помогли.

+1949
источник поделиться
25 ответов

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

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

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

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

+966
источник

В языке, реализующем классическое наследование типа 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);
+1779
источник

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

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.

The prototype chain

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

+170
источник

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 сообщества, поэтому люди могут исправить меня, если я ошибаюсь.

+74
источник

Семь Коанов-прототипов

Когда Чиро Сан спустился с Горы Огненной Лисы после глубокой медитации, его разум был чист и спокоен.

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


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
+68
источник

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

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

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

и

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

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

Цепочка прототипа

в конечном счете возвращается к Object.prototype.

Цепочка прототипа

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

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

+64
источник

Каждый объект имеет внутреннее свойство [[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.
+37
источник

Эта статья длинна. Но я уверен, что это очистит большинство ваших запросов в отношении "прототипического" характера наследования 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.

Надеюсь, что это поможет.

+26
источник

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

цепочка прототипов

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

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

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

+25
источник

Концепция наследования 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, которое ниже суммирует всю большую диаграмму.

введите описание изображения здесь

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

+22
источник

Какова цель этого свойства ".prototype"?

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

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

+20
источник

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

Рассмотрим конструктор:

 function Person() {}

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

Цепочка в направлении вверх выглядит следующим образом:

    PersonFunction.prototypeObject.prototype (конечная точка)

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

Возьмем, к примеру, этот объект:

var p = new Person();

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

    pPerson.prototypeObject.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:

    tpPerson.prototypeObject.prototype (конечная точка)

Другая цепочка прототипов не больше: Thief и Person являются братьями и сестрами, разделяющими один и тот же родительский элемент в цепочке прототипов:

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

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

введите описание изображения здесь

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

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

Окончательное руководство по объектно-ориентированному JavaScript - очень краткое и понятное объяснение 30-минутного вопроса по заданному вопросу (тема Prototypal Inheritance начинается с 5:45, хотя я бы предпочел слушать все видео). Автор этого видео также сделал сайт JavaScript-визуализатора JavaScript http://www.objectplayground.com/. введите описание изображения здесь введите описание изображения здесь

+16
источник

Мне было полезно объяснить "цепочку прототипов" как рекурсивное соглашение, когда ссылается obj_n.prop_X:

если obj_n.prop_X не существует, проверьте obj_n+1.prop_X где obj_n+1 = obj_n.[[prototype]]

Если prop_X наконец-то найден в k-м прототипе объекта, то

obj_1.prop_X = obj_1.[[prototype]].[[prototype]]..(k-times)..[[prototype]].prop_X

Вы можете найти график зависимости объектов Javascript от их свойств здесь:

js objects graph

http://jsobjects.org

+14
источник

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

+13
источник

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

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

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 называется прототипным наследованием. Там, так просто, согласитесь?

+10
источник

Здесь есть две разные, но взаимосвязанные сущности, которые нужно объяснить

  • Свойство .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.

+10
источник

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

+9
источник

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

Simple objects inheritanse

+8
источник

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

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

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

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

Важно то, что Дерп не дает вам ручку, так как у вас нет прямых отношений с ним.

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

+7
источник

Резюме:

  • Функции являются объектами в JavaScript и, следовательно, могут иметь свойства
  • (Конструктор) функции всегда имеют свойство прототипа
  • Когда функция используется в качестве конструктора с ключевым словом new объект получает прототип. Ссылку на этот прототип можно найти в __proto__ вновь созданного объекта.
  • Это свойство __proto__ ссылается на свойство prototype функции конструктора.

Пример:

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

let me = new Person('willem');

console.log(Person.prototype) // Person has a prototype property

console.log(Person.prototype === me.__proto__) // the __proto__ property of the instance refers to prototype property of the function.

Почему это полезно:

Javascript имеет механизм поиска свойств в объектах, который называется "наследование прототипов", вот что в основном делает:

  • Сначала проверяется, находится ли свойство на самом объекте. Если это так, это свойство возвращается.
  • Если свойство не находится на самом объекте, оно "поднимется по проточине". Он в основном смотрит на объект, на который ссылается свойство proto. Там он проверяет, доступно ли свойство для объекта, на который ссылается прото
  • Если свойство не находится на объекте прото, оно будет подниматься вверх по цепи прото до объекта Object.
  • Если он не может найти свойство нигде в объекте и его цепочке прототипов, он вернет неопределенное.

Например:

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

let mySelf = new Person('Willem');

console.log(mySelf.__proto__ === Person.prototype);

console.log(mySelf.__proto__.__proto__ === Object.prototype);

Обновить:

Свойство __proto__ устарело, хотя оно реализовано в большинстве современных браузеров, и лучший способ получить ссылку на объект-прототип:

Object.getPrototypeOf()

+4
источник

другая схема, показывающая __proto__, отношения между прототипом и конструктором: enter image description here

+3
источник

Просто у вас уже есть объект с Object.new но у вас все еще нет объекта при использовании синтаксиса конструктора.

+2
источник

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

+2
источник

Важно понимать, что существует различие между прототипом объекта (который доступен через Object.getPrototypeOf(obj) или через устаревшее свойство __proto__) и свойством prototype в функциях конструктора. Первый является свойством каждого экземпляра, а второй - свойством конструктора. То есть Object.getPrototypeOf(new Foobar()) ссылается на тот же объект, что и Foobar.prototype.

Ссылка: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes

0
источник

Посмотрите другие вопросы по меткам или Задайте вопрос