Как работает JavaScript .prototype?

Это довольно старый вопрос, но я использовал

. Мой метод имеет этот параметр, но он может быть построен:

Expression<Func<TModel, TValue>> expression

Затем в методе this:

System.Linq.Expressions.MemberExpression memberExpression 
       = expression.Body as System.Linq.Expressions.MemberExpression;
Boolean hasIdentityAttr = System.Attribute
       .IsDefined(memberExpression.Member, typeof(IsIdentity));
1950
задан John Leidegren 19 August 2018 в 11:52
поделиться

25 ответов

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

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

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

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

967
ответ дан Christoph 19 August 2018 в 11:52
поделиться

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

Simple objects inheritanse

8
ответ дан rus1 19 August 2018 в 11:52
поделиться

Резюме:

  • Функции являются объектами в 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 . Там он проверяет, доступно ли свойство на объекте, указанном в proto
  • Если свойство не находится на объекте proto , оно поднимется вверх по прото цепочка до объекта Object.
  • Если он не может найти свойство нигде в объекте и его цепочке прототипов, он вернет undefined.

Например:

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
ответ дан Willem van der Veen 19 August 2018 в 11:52
поделиться

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

13
ответ дан Tom 19 August 2018 в 11:52
поделиться

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

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

0
ответ дан Pang 19 August 2018 в 11:52
поделиться

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

  • Свойство .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
ответ дан Palec 19 August 2018 в 11:52
поделиться

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

2
ответ дан Pang 19 August 2018 в 11:52
поделиться

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

3
ответ дан IvanM 19 August 2018 в 11:52
поделиться

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

http://iwiki.readthedocs.org/en/latest/javascript/js_core.html# наследование *[[protytype]]* and <code>prototype</code> property of function objects

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

и

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

, который содержит пример с кодом и несколько симпатичных диаграмм.

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

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

Надеюсь, вам также полезно понять цепь прототипов JavaScript.

64
ответ дан lcn 19 August 2018 в 11:52
поделиться

Я нашел полезным объяснить «цепочку прототипов» как рекурсивное соглашение, когда на 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
ответ дан B M 19 August 2018 в 11:52
поделиться

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

0
ответ дан Arif 19 August 2018 в 11:52
поделиться

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

16
ответ дан Bad 19 August 2018 в 11:52
поделиться

Рассмотрим следующий объект 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
ответ дан John Slegers 19 August 2018 в 11:52
поделиться

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.

Выше мое понимание. Я делаю это вики-сообществом, чтобы люди могли поправить меня, если я ошибаюсь.

74
ответ дан 3 revs, 2 users 93% 19 August 2018 в 11:52
поделиться

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

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

 function Person() {}

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

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

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

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

.

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

var p = new Person();

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

& nbsp; & nbsp; & nbsp; pPerson.prototypeObject.prototype (конечная точка)

В этой цепочке нет функционального объекта (хотя это может быть).

Таким образом, Person кажется связанным с двумя видами цепей, которые живут своей жизнью. Чтобы «перепрыгнуть» из одной цепочки в другую, вы используете:

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

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

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

enter image description here

[1183]

Подводя итог:

Свойство prototype не дает информации о цепочке прототипов субъекта , но об объектах , созданных субъектом.

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

Вы можете переключаться между двумя цепочками прототипов:

Person.prototype.constructor === Person

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

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

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

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

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

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

Вот некоторые равенства, которые могут помочь понять проблему - все эти печати 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();

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

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

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

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

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

enter image description here

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

  • между объектом и его конструктором
  • между конструктором и объектом-прототипом, который будет использоваться для конструирования объектов
19
ответ дан trincot 19 August 2018 в 11:52
поделиться

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

object [[Prototype]] -> anotherObject

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

object [[Prototype]] -> aFunction.prototype

В некоторых средах [[Prototype]] отображается как __proto__:

anObject.__proto__ === anotherObject

При создании объекта создается ссылка [[Prototype]].

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

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

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

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

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

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

Помните:

  • Каждый объект имеет ссылку [[Prototype]], иногда отображаемую как __proto__.
  • Каждая функция имеет свойство prototype.
  • Объекты, созданные с помощью new, связаны со свойством prototype их конструктора.
  • Если функция никогда не используется в качестве конструктора, ее свойство prototype останется неиспользованным.
  • Если вам не нужен конструктор, используйте Object.create вместо new.
  • [Тысяча сто двадцать девять]
37
ответ дан sam 19 August 2018 в 11:52
поделиться

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

//The following statement generates an error.
john.setAmountDue(1000);
1780
ответ дан Tushar Gupta - curioustushar 19 August 2018 в 11:52
поделиться

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

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

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

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

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

25
ответ дан Georg Schölly 19 August 2018 в 11:52
поделиться

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

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

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

20
ответ дан dirkgently 19 August 2018 в 11:52
поделиться

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

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

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

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

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

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

7
ответ дан Louis Moore 19 August 2018 в 11:52
поделиться

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

enter image description here

Если мы используем оператор new в Tree function, мы называем его функцией constructor.

enter image description here

Каждая функция JavaScript имеет prototype. Когда вы регистрируете Tree.prototype, вы получаете ...

enter image description here

Если вы посмотрите на вышеприведенный вывод 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's prototype.

enter image description here

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

Давайте добавим метод к нашему Tree prototype.

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. В этом случае мы устанавливаем прототип Child для нового объекта, который выглядит идентично прототипу 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, от которого наследует Child.

enter image description here

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

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

enter image description here

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

Вот что происходит за кулисами: // что делает движок JavaScript

enter image description here

String object существует только за один оператор до его уничтожения (процесс под названием autoboxing). Давайте снова вернемся к нашему prototypal inheritance.

  • Javascript поддерживает наследование через delegation на основе prototypes.
  • Каждый Function имеет свойство prototype, которое относится к другому объекту.
  • properties/functions просматриваются из самого object или через цепочку prototype, если он не существует

A prototype в JS - это объект, который yields указывает вам на родитель другого object. [то есть .. делегирование] Delegation означает, что если вы не в состоянии что-то сделать, вы скажете кому-то другому сделать это для вас.

enter image description here

https://jsfiddle.net/say0tzpL/1/

Если вы посмотрите вверх выше скрипки собака имеет доступ к методу toString, но в нем его нет, но доступны через цепочку прототипов, которая делегирует Object.prototype

enter image description here

Если вы посмотрите на приведенную ниже, мы пытаемся получить доступ к call метод, который доступен в каждом function.

enter image description here

https://jsfiddle.net/rknffckc/

Если вы посмотрите вышеупомянутую скрипку , Profile Функция имеет доступ к методу call, но недоступна в нем, но доступна через цепочку прототипов, которая делегирует Function.prototype

enter image description here

Примечание: prototype является свойством конструктора функции, тогда как __proto__ является свойством объектов, созданных из конструктора функции. Каждая функция имеет свойство prototype, значение которого является пустым object. Когда мы создаем экземпляр функции, мы получаем внутреннее свойство [[Prototype]] или __proto__, ссылка на который является прототипом функции constructor.

enter image description here

Вышеприведенная диаграмма выглядит немного сложнее, но дает полную картину того, как работает prototype chaining. Давайте медленно пройдемся по этому: 11100] и Foo

enter image description here

https://jsfiddle.net/kbp7jr7n/

Если вы посмотрите код выше, у нас есть конструктор Foo, у которого есть метод identify() и конструктор Bar, у которого есть метод speak. Мы создаем два экземпляра Bar b1 и b2, родительский тип которых Foo. Теперь, вызывая метод speak из Bar, мы можем определить, кто вызывает речь, по цепочке prototype.

enter image description here

Bar теперь имеет все методы Foo, которые определены в его prototype. Давайте углубимся в понимание Object.prototype и Function.prototype и как они связаны. Если вы посмотрите конструктор Foo, Bar и Object - это Function constructor.

enter image description here

prototype в Bar - это Foo, prototype в Foo - Object, и если вы посмотрите внимательно prototype из Foo относится к Object.prototype. ​​

enter image description here

Прежде чем мы закроем это, давайте просто завернем небольшой фрагмент кода здесь, чтобы суммировал все выше . Мы используем здесь оператор instanceof, чтобы проверить, имеет ли object в своей цепочке prototype свойство prototype для constructor, которое ниже суммирует всю большую диаграмму.

enter image description here

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

22
ответ дан Thalaivar 19 August 2018 в 11:52
поделиться

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

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

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


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 свойства добавлены со свойствами 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. Наши две строки кода созданы только 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
ответ дан Ciro Santilli 新疆改造中心996ICU六四事件 19 August 2018 в 11:52
поделиться

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

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

Есть несколько важных моментов, которые мы должны рассмотреть прежде чем перейти к концепции прототипа.

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

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

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

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

Первым вопросом было бы , как ключевое слово this могло бы быть полезным без использования ключевого слова new . ​​

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

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

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

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

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

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

в данном случае это будет текущий объект контекста, который обычно является глобальным объектом window в браузере или GLOBAL ] в Node.js. Это означает, что у нас будет window.name в браузере или GLOBAL.name в Node.js со значением «George».

[+1178] б. Мы можем прикрепить их к объекту, так как его свойства

- Самый простой способ сделать это - изменить пустой объект person, например:

person.Person = Person;
person.getName = getName;

таким образом мы можем назвать их как:

person.Person("George");
person.getName();// -->"George"

и теперь объект person имеет вид:

Object {Person: function, getName: function, name: "George"}

- Другой способ прикрепить свойство к объекту - использовать prototype этого объекта, который можно найти в любом объекте JavaScript с именем __proto__, и я попытался объяснить его немного в итоговой части. , Таким образом, мы могли бы получить аналогичный результат, выполнив:

person.__proto__.Person = Person;
person.__proto__.getName = getName;

Но таким образом, что мы на самом деле делаем, это модифицируем Object.prototype, потому что всякий раз, когда мы создаем объект JavaScript с использованием литералов ( { ... }), он создается на основе Object.prototype, что означает, что он присоединяется к вновь созданному объекту как атрибут с именем __proto__ , поэтому, если мы изменим его, как мы это сделали на нашем предыдущий фрагмент кода, все объекты JavaScript будут изменены, не очень хорошая практика. Итак, что может быть лучшей практикой сейчас:

person.__proto__ = {
    Person: Person,
    getName: getName
};

и теперь другие объекты в мире, но это все еще не кажется хорошей практикой. Таким образом, у нас есть еще одно решение, но чтобы использовать это решение, мы должны вернуться к той строке кода, где объект person был создан (var person = {};), а затем изменить его следующим образом:

var propertiesObject = {
    Person: Person,
    getName: getName
};
var person = Object.create(propertiesObject);

что это делает создает новый JavaScript Object и присоединяет propertiesObject к атрибуту __proto__. Итак, чтобы убедиться, что вы можете сделать:

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

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


, как вы видите, используя любой из этих двух способов, this будет точно указывать на объект person.

[+1179] с. У JavaScript есть другой способ предоставить функцию с помощью this, которая использует вызов или apply для вызова функции.

Метод apply () вызывает функцию с заданным значением this и аргументами, представленными в виде массива (или подобного массиву объекта).

и

Метод call () вызывает функцию с заданным значением и аргументами, предоставляемыми индивидуально.

таким образом, который является моим любимым, мы можем легко назвать наши функции, такие как:

Person.call(person, "George");

или

//apply is more useful when params count is not fixed
Person.apply(person, ["George"]);

getName.call(person);   
getName.apply(person);

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


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, один за другим:

a. во-первых, он создает пустой объект, в основном пустой хэш, например:

var newObject = {};

b. следующий шаг, который делает 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();

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

, мы можем сделать это с нашим примером, например:

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__ равен нулю. Точка - единственный объект в JavaScript, для которого его атрибут __proto__ имеет значение NULL, это Object.prototype объект:

console.log(Object.prototype.__proto__===null);//true

, и именно так наследование работает в JavaScript.

The prototype chain

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

172
ответ дан Mehran Hatami 19 August 2018 в 11:52
поделиться

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

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

  • Необъекты
  • Объекты

Необъекты

Ниже приведены Необъект типы

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

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

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

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

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

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

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

Объекты

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

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

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

  • Объект
  • Строка
  • Число
  • Логическое значение
  • Массив
  • Типизированные массивы
  • RegExp
  • Функция
  • Все остальные встроенные объекты, которые могут создавать новые объекты с помощью оператора new
  • Функция UserDefinedFunction () {/ * пользовательский код * /}

Итак, typeof (объект) === typeof (строка) === typeof (число ) === typeof (логическое значение) === typeof (массив) === typeof (RegExp) === typeof (Функция) === typeof (UserDefinedFunction) === 'function'

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

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")

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

Все созданные таким образом объекты являются Объектами не функционального типа и возвращают свои TypeOf === 'объект' . Во всех этих случаях объект «а» не может в дальнейшем создавать объекты, используя оператор 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'

Также обратите внимание, что функции Object , Array и 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 объекты типа ).

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

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

Кроме того, каждый созданный объект ( Тип функции или Не тип функции ) имеет «конструктор» свойство, которое унаследовано от объекта, на который ссылается свойство prototype функции Constructor. По умолчанию это свойство «constructor» ссылается на функцию-конструктор , которая его создала (если «прототип» функции функции-конструктора по умолчанию не изменился).

Для всех объектов типа функции функцией конструктора всегда является function 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
  • Простые объекты (созданные новым Object () или {}, включая встроенные Math object) -> Object.prototype -> null
  • Объект, созданный с помощью new или Object.create -> Одна или несколько цепочек прототипов -> 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 . Созданные таким образом объекты являются объектами нефункционального типа . Объекты не-типа не могут в дальнейшем создавать объект с помощью оператора new .

  • Все объекты типа функции по умолчанию имеют свойство «prototype» . Это свойство «prototype» ссылается на объект, имеющий свойство «constructor» , которое по умолчанию ссылается на сам объект типа функции .

  • Все объекты ( Тип функции и Не тип функции ) имеют свойство «конструктор», которое по умолчанию ссылается на тип функции объект / Конструктор , который его создал.

  • Каждый создаваемый объект внутренне ссылается на объект, на который ссылается свойство «prototype» конструктора, который его создал. Этот объект известен как прототип созданного объекта (который отличается от свойства «prototype» объектов функции, на которое он ссылается). Таким образом, созданный объект может напрямую обращаться к методам и свойствам, определенным в объекте, на который ссылается свойство «прототипа» конструктора (во время создания объекта).

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

  • Цепочка прототипов каждого объекта в конечном счете восходит к Object.prototype (если объект не создан с использованием Object.create (null), в этом случае у объекта нет прототипа).

  • typeof (new Array ()) === 'object' является языком и не является ошибкой, на что указывал Дуглас Крокфорд

  • Установка для свойства prototype конструктора значения null (или неопределенного, number, true, false, string) не должна создавать объект с нулевым прототипом. В таких случаях для вновь созданного прототипа объекта устанавливается Object.prototype, а для его конструктора устанавливается функция Object.

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

26
ответ дан Arup Hore 19 August 2018 в 11:52
поделиться

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

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

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

Каждый объект содержит внутреннее свойство, называемое [[prototype]], к которому может обращаться функция Object.getPrototypeOf(). Object.create(model) создает новый объект и устанавливает его свойство [[prototype]] для модели объекта . Следовательно, когда вы сделаете Object.getPrototypeOf(product), вы получите объект модель .

Свойства в продукте обрабатываются следующим образом:

  • Когда к свойству обращаются, чтобы просто прочитать его значение, оно ищется в цепочке областей действия. Поиск переменной начинается с продукта и выше до его прототипа. Если такая переменная найдена в поиске, поиск тут же останавливается, и возвращается значение. Если такая переменная не может быть найдена в цепочке областей действия, возвращается undefined.
  • Когда свойство записывается (изменяется), свойство всегда записывается в объекте product . Если продукт еще не имеет такого свойства, он неявно создается и записывается.

Такое связывание объектов с использованием свойства прототипа называется прототипным наследованием. Там так просто, согласен?

10
ответ дан Aravind 19 August 2018 в 11:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: