Запутался насчет наследования прототипов JavaScript - PullRequest
3 голосов
/ 02 февраля 2010

В книге " JavaScript полное руководство 5 издание ", раздел 9.2 Прототипы и наследование я нахожу следующие слова:

В предыдущем разделе я показал, что новый оператор создает новый, пустой объект, а затем вызывает конструктор функционировать как метод этого объекта. Это не полная история, тем не мение. После создания пустого объект, новый устанавливает прототип этого объект. Прототип объекта Значение свойства прототипа его функция конструктора. Все функции имеют свойство прототипа это автоматически создается и инициализируется, когда функция определены. Начальное значение Свойство прототипа представляет собой объект с единственная собственность. Это свойство именованный конструктор и ссылается на функция конструктора, с которой с прототипом связан. (Вы может вспомнить свойство конструктора из главы 7; Вот почему каждый Объект имеет свойство конструктора.) Любые свойства, которые вы добавляете к этому объект-прототип будет казаться свойства объектов, инициализированных конструктор.

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

Ответы [ 4 ]

15 голосов
/ 02 июня 2016

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

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

const myCar = new Racecar();
console.log(myCar.constructor); // [Function: Racecar]

const car2 = new myCar.constructor();
console.log(car2.constructor); // [Function: Racecar]

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

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

Лучший способ узнать, является ли что-либо совместимым типом, - это проверить свойства объекта.Другими словами, тип утки.

Оператор instanceof игнорирует свойство .constructor.Вместо этого он проверяет, существует ли конструктор .prototype (с проверкой идентичности) в цепочке прототипов объекта.

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

function Car () {}

console.log(Car.prototype.constructor); // Car

function Racecar () {}

Racecar.prototype = Object.create(Car.prototype);
// To preserve the same relationship we have with the Car
// constructor, we'll need to reassign the .prototype.constructor:
Racecar.prototype.constructor = Racecar;

var myCar = new Racecar();
console.log(myCar.constructor); // [Function: Racecar]

Классы ES6 делают это автоматически:

// ES6
class Car {}
class Racecar extends Car {}

const myCar = new Racecar();
console.log(myCar.constructor); // [Function: Racecar]

Тем не менее, я не большой поклонниклибо функций конструктора, либо классов ES6, и я обычно мало пользуюсь свойством .constructor.Зачем?Поскольку фабричные функции гораздо более гибкие, гораздо более мощные, и у них нет ловушек, связанных с функциями конструктора и наследованием классов.См. «Фабричные функции против функций конструктора против классов» .

8 голосов
/ 02 февраля 2010

Скажем, собака - это млекопитающее.

<code>function Mammal() {
  this.milk = true;
};</p>

<p>function Dog() {
  this.bark = true;
}
Dog.prototype = new Mammal;

Таким образом, прототип собаки указывает на объект Млекопитающего . Этот объект Mammal имеет ссылку на его конструктор, поэтому, когда Dog является новым, JavaScript видит, что прототип Dog является Mammal, поэтому конструктор Mammal вызывается для создания допустимого объекта Mammal (еще один), а затем делает его объектом Dog с помощью конструктора Dog. *

Исходя из этого, конструктором Dog.prototype является Mammal (объект-млекопитающее, к которому добавлены дополнительные поля и функции), но НО-конструктором Dog является Dog. Наследование существует, потому что экземпляр Dog имеет Млекопитающее в качестве прототипа; следовательно, собака млекопитающее. Когда метод вызывается и JS не может найти его из Dog.prototype, JS ищет в Mammal.prototype (это объект, в который добавлены дополнительные поля и функции).

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

2 голосов
/ 02 февраля 2010

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

Если вы все еще не уверены в своем понимании, поищите в Google __proto__ - внутреннюю ссылку на прототип объектов JS.Он даже подвергается воздействию скриптов в Firefox и Safari.

Хороший справочник: https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/The_Employee_Example/Object_Properties/Inheriting_Properties

1 голос
/ 02 февраля 2010

Если у вас есть объект obj, его прототип - obj.prototype, а свойство конструктора, ссылающееся на конструктор obj, - obj.prototype.constructor.

Для объекта obj.prototype ситуация такова:так же.Допустим, proto = obj.prototype, тогда ссылка на конструктор proto будет найдена в proto.prototype.constructor.

Это то же самое, что и obj.prototype.prototype.constructor, поэтому нет конфликта с obj.prototype.constructor.

...