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


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

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

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

но какова точная цель этого ".свойство "прототип" в JavaScript? Как это связано с созданием экземпляров объектов?

обновление: правильный путь

var obj = new Object(); // not a functional object
obj.prototype.test = function() { alert('Hello?'); }; // this is wrong!

function MyObject() {} // a first class functional object
MyObject.prototype.test = function() { alert('OK'); } // OK

эти горки действительно очень помогли.

23   1883   2009-02-21 15:31:18

23 ответа:

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

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

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

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

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

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

пример:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

Итак, чтобы ответить на этот вопрос допустим, у нас есть пустой объект, и две функции, как:

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

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

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

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

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

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

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

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


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

newObject.getName();

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

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

Person.call(newObject, "George");

или

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

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

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


резюме:

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

new FunctionName()

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

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

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

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

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

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

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

function obj()
{
}

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

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

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

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

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

и

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

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

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

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

надеюсь, что это также полезно для вас, чтобы понять JavaScript Prototype Chain.

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


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

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

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

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

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


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

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

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


2)

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

порядок просмотра это:

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

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

object [[Prototype]] -> anotherObject

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

object [[Prototype]] -> aFunction.prototype

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

anObject.__proto__ === anotherObject

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

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

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

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

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

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

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

помните:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

объекты

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

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

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

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

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

все функции объекты типа на самом деле являются экземплярами встроенного объекта 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")

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

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

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

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

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

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

var a=String() // Create a new Non Object string. returns a typeof==='string' 
var a=Number() // Create a new Non Object Number. returns a typeof==='number'
var a=Boolean() //Create a new Non Object Boolean. returns a typeof==='boolean'

пользовательские функции являются особым случаем.

var a=UserDefinedFunction() //may or may not create an object of type UserDefinedFunction() based on how it is defined.

С функции объекты типа создавать новые объекты, они также называются конструкторы.

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

например, когда мы определяем функцию

function UserDefinedFunction()
{
}

после автоматически бывает

UserDefinedFunction.prototype={constructor:UserDefinedFunction}

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

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

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

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

enter image description here

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

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

это такие вещи, как .toString, .toValue, .hasOwnProperty etc...

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

enter image description here

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

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

enter image description here

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

enter image description here

это означает, что при создании instance на Tree вы можете называть это branch метод.

enter image description here

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

enter image description here

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

enter image description here

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

enter image description here

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

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

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

enter image description here

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

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

enter image description here

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

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

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

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

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

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

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

 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 кажется, связано с двумя видами о цепях, которые живут своей собственной жизнью. Чтобы "перепрыгнуть" с одной цепи на другую, вы используете:

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

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

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

enter image description here

в итоге:

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

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

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

Person.prototype.constructor === Person

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

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

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

  1. функции
  2. объект, который будет действовать как прототип, когда функция вызывается как конструктор

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

вот некоторые равенства, которые могли бы помочь понять проблему - все эти печати true:

function Person() {};

// This is prototype chain info for the constructor (the function object):
console.log(Object.getPrototypeOf(Person) === Function.prototype);
// Step further up in the same hierarchy:
console.log(Object.getPrototypeOf(Function.prototype) === Object.prototype);
console.log(Object.getPrototypeOf(Object.prototype) === null);
console.log(Person.__proto__ === Function.prototype);
// Here we swap lanes, and look at the constructor of the constructor
console.log(Person.constructor === Function);
console.log(Person instanceof Function);

// Person.prototype was created by Person (at the time of its creation)
// Here we swap lanes back and forth:
console.log(Person.prototype.constructor === Person);
// Although it is not an instance of it:
console.log(!(Person.prototype instanceof Person));
// Instances are objects created by the constructor:
var p = new Person();
// Similarly to what was shown for the constructor, here we have
// the same for the object created by the constructor:
console.log(Object.getPrototypeOf(p) === Person.prototype);
console.log(p.__proto__ === Person.prototype);
// Here we swap lanes, and look at the constructor
console.log(p.constructor === Person);
console.log(p instanceof Person);

добавление уровней в цепочку прототипов

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

например:

function Thief() { }
var p = new Person();
Thief.prototype = p; // this determines the prototype for any new Thief objects:
var t = new Thief();

теперь прототип цепи t на один шаг больше, чем у p:

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

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

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

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

enter image description here

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

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

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

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

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

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

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

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

js objects graph

http://jsobjects.org

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

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

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

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

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

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

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

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

  • The .prototype свойства функций.
  • The [[Prototype]][1] свойства всех объектов[2].

это две разные вещи.

The [[Prototype]] свойства:

это свойство, которое существует на всех[2] объекты.

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

The [[Prototype]] свойство является частью того, что образует [[Prototype]] цепи. Эта цепочка [[Prototype]] объекты-это то, что изучается, когда, для например, [[Get]] или [[Set]] операции выполняются над объектом:

var obj = {}
obj.a         // [[Get]] consults prototype chain
obj.b = 20    // [[Set]] consults prototype chain

The .prototype свойства:

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

function Bar(){};

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

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

вот так .prototype это объект, он имеет [[Prototype]] собственность. Когда вы не делаете никаких назначений Function.prototype на .prototype ' s [[Prototype]] указывает на прототипический объект (Object.prototype). Это выполняется автоматически при создании новой функции.

таким образом, в любое время вы new Bar; прототип цепи настроен для вас, вы получите все, что определено на Bar.prototype и все, что определено на Object.prototype:

var b = new Bar;
// Get all Bar.prototype properties
console.log(b.__proto__ === Bar.prototype)
// Get all Object.prototype properties
console.log(b.__proto__.__proto__ === Object.prototype)

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

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


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

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

Simple objects inheritanse

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

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

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

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

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

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

резюме:

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

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

например:

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

let mySelf = new Person('Willem');

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

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

Это просто, что у вас уже есть объект с объектом.новый, но у вас все еще нет объекта при использовании синтаксиса конструктора.

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