Подтвердить что ты не робот

Попытка понять разницу между прототипом и конструктором в JavaScript

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

Путаница возникает, когда люди говорят о конструкторе и прототипе одновременно.

В следующем примере

var employee = function Emp(name) {
    this.name = name;
}
var jack = new employee("Jack Dwain");

employee.constructor //gives Function()

employee.prototype // gives  Emp {}

employee.prototype.constructor //gives Emp(name)

jack.constructor //gives Emp(name)

jack.prototype //gives undefined
  • прототип - это способ, которым JS достигает наследования, поскольку Emp(name) - это прототип базовой функции, который ссылается на ту же самую функцию. Это то, что произошло?

  • Чем отличаются employee.constructor и employee.prototype.constructor?

  • Почему jack.prototype был undefined i.e Если он наследует от функции Emp(name), почему он не ссылается на эту функцию?

  • Как я могу четко предсказать себя, не набрав в консоли то, что прототип, или конструктор, или prototype.constructor...... дает

4b9b3361

Ответ 1

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

Все функции имеют прототип Function(). Они наследуют все базовые функциональные возможности от Function, такие как toString() и valueOf().

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

p = new Foo();

Так что в этом случае у нас есть две вещи.

  • function Foo с Function качестве прототипа (Foo)
  • Объект Function с Foo() качестве конструктора (p)

(следите за мной еще?)

Конструктор Foo() может переопределить некоторые базовые функциональные возможности конструктора Function, но также оставить его как есть и эффективно его использовать.

Если вы знакомы с принципами ООП, то прототип - это базовый класс, конструктор - ваш текущий класс. в ООП выше будет class Foo extends Function

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

Например это:

// make a object initialiser extending Function. in oop 'class Foo extends Function'

function Foo(bar) {
    this.baz = bar;
}
Foo.prototype.append = function(what) {
    this.baz += " " + what;
};
Foo.prototype.get() {
    return this.baz
}

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

Поэтому нам нужно расширить его, чтобы использовать термин ООП. в OOp это будет желаемый конечный class Title extends Foo(){} результатов class Title extends Foo(){}. Итак, давайте посмотрим, как туда добраться.

function Title(what) {
    this.message = what;
}

На данный момент функция Title выглядит следующим образом:

  • Функция прототипа
  • Название конструктора

Итак, чтобы расширить его, нам нужно изменить прототип.

Title.prototype = new Foo();
  • прототип Foo
  • конструктор Фу

Это делается путем инициализации нового объекта Foo() против прототипа. Теперь это в основном объект Foo с названием Title. Это не то, что мы хотим, потому что теперь мы не можем получить доступ к части сообщения в заголовке. Мы можем заставить его правильно расширять Foo(), сбрасывая конструктор в Title

Title.prototype.constructor = Title;
  • прототип Foo
  • Название конструктора

Теперь мы столкнулись с еще одной проблемой. Конструктор Foo не инициализируется, поэтому мы получаем неопределенный this.baz

Чтобы решить это нам нужно позвонить родителю. В Java вы можете сделать это с помощью super(vars), в php $parent->__construct($vars).

В javascript мы должны изменить конструктор класса Title для вызова конструктора родительского объекта.

Таким образом, конструктор класса Title станет

function Title(what) {
    Foo.call(this,what);
    this.message = what;
}

Используя свойство объекта Function, унаследованное от Foo, мы можем инициализировать объект Foo в объекте Title.

И теперь у вас есть правильно унаследованный объект.

Таким образом, вместо использования такого ключевого слова, как extend как в других языках ООП, он использует prototype и constructor.

Ответ 2

employee.constructor//дает функцию()

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

var employee2 = new Function('a', 'b', 'return a+b');

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

employee.prototype//дает Emp {}

Каждый объект в JavaScript имеет прототип, связанный с ним. Хотя прототип объектов объектов напрямую доступен с помощью .prototype. Этот же прототип копируется на прототипе объектов, когда вы создаете объекты с ключевым словом new. В первую очередь это копирование отвечает за наследование/расширение. Несмотря на то, что прототип скопирован, он не имеет прямого доступа, как в случае объектов Function. Он доступен нестандартным способом с помощью .__proto__. Следующий код вернет true.

jack.__proto__==employee.prototype

employee.prototype.constructor//дает Emp (name)

Как сказано в документации Object.prototype.constructor. Это возвращает ссылку на функцию Object, которая создала прототип экземпляра. Здесь ссылается объект employee.prototype и not employee. Это немного сложно, но прототип объекта employee.prototype был создан функцией Emp (name)

jack.constructor//дает Emp (имя)

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

jack.prototype//дает undefined

Разъем

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

jack.__proto__

Ответ 3

Если вы хотите создать javascript объект, вы можете просто объявить новый объект и присвоить ему свойства (я решил объективировать себя):

var myself= {
    name:"Niddro",
    age:32
};

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

//Constructor
function generalNameForObject(param1, param2,...) {
    //Give the object some properties...
}

У меня есть прототип (приемник) в виду, что я хочу позвонить человеку, и он должен содержать имя и возраст свойств, и я буду использовать конструктор, чтобы сделать это:

function person(name,age) {
    this.name=name;
    this.age=age;
}

Вышеупомянутая функция построения описывает прототип для моих личных объектов.

Создайте нового человека, вызвав функцию construct:

var myself = new person("Niddro",31);
var OP = new person("rajashekar thirumala",23);

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

myself.age=32;

Если вы хотите добавить свойства в конструкцию, вам необходимо вручную добавить ее в конструктор:

function person(name,age,rep) {
    this.name=name;
    this.age=age;
    this.reputation=rep;
}

Вместо этого вы можете добавить свойства прототипу, выполнив следующие действия (здесь "prototype" - действительная команда, а не просто имя):

function person(name,age,rep) {
    this.name=name;
    this.age=age;
}
person.prototype.reputation=105;

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

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

Ответ 4

Конструктор:

function Foo(x) {
    this.x =x;
}

Foo является конструктором. Конструктор - это функция.

Существует два способа использования этого конструктора Foo.

"Объекты создаются с использованием конструкторов в новых выражениях, для Например, новая дата (2009,11) создает новый объект Date. Вызов конструктор без использования новых имеет последствия, которые зависят от конструктор. Например, Date() создает строковое представление текущую дату и время, а не объект."

Источник ECMA-262

Это означает, что если Foo возвращает что-то (через return "somevalue";), то typeof Foo() - тип возвращаемого значения.

С другой стороны, когда вы вызываете

var o = new Foo();

JavaScript фактически просто

var o = new Object();
o.[[Prototype]] = Foo.prototype;
Foo.call(o);

Прототип:

Когда вы вызываете o.a, тогда javascript сначала проверяет, является ли a собственное свойство объекта o. Если javascript не ищет цепочку свойств, найдите a.

Для получения дополнительной информации о цепочке свойств см. mdn.

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

Резюме:

Примечание. Это не точное определение, цель сводки - просто дать вам представление об участниках и прототипах.

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

Ответ 5

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