В чем причина использования ключевого слова "новое" в Derived.prototype = new Base

Что делает следующий код:

WeatherWidget.prototype = new Widget;

где Widget - конструктор, и я хочу расширить класс Widget с помощью новой функции WeatherWidget.

Что такое ключевое слово new, и что произойдет, если его не учитывать?

Ответ 1

WeatherWidget.prototype = new Widget;

Ключевое слово new вызывает Widget как конструктор, а возвращаемое значение присваивается свойству prototype. (Если вы опустите new, вы не будете называть Widget, если вы не добавили список аргументов, (). Однако вызов этого метода был бы невозможен. Это, безусловно, потенциально может испортить глобальный пространство имен, если это не строгий режимный код, и реализация соответствует ECMAScript Ed. 5.x, потому что тогда this в конструкторе будет ссылаться на глобальный объект ECMAScripts.)

Но этот подход на самом деле происходит от действительно вирусного плохой пример в старом Netscape JavaScript 1.3 Guide (отражается в Oracle, ранее Sun).

Таким образом, ваши экземпляры WeatherWidget будут наследоваться от одного и того же экземпляра Widget. Цепочка прототипа будет:

[new WeatherWidget()] → [new Widget()] → [Widget.prototype] → …

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

Правильный способ реализации наследования на основе классов на этих языках, основанных на прототипах (первоначально был разработан Lasse Reichstein Nielsen в comp.lang.javascript в 2003 году, для клонирование объектов):

function Dummy () {}
Dummy.prototype = Widget.prototype;
WeatherWidget.prototype = new Dummy();
WeatherWidget.prototype.constructor = WeatherWidget;

Свойство prototype constructor также должно быть исправлено, так что ваши экземпляры WeatherWidget w имели бы w.constructor === WeatherWidget, как ожидалось, а не w.constructor === Widget. Однако имейте в виду, что он перечислим впоследствии.

Таким образом, экземпляры WeatherWidget наследуют свойства через цепочку прототипов, но не будут делиться значениями свойств между ними, поскольку они наследуют от Widget.prototype до Dummy, который не имеет собственных свойств:

[new WeatherWidget()] → [new Dummy()] → [Widget.prototype] → …

В реализациях ECMAScript Ed. 5 и более поздних версий, вы можете и должны использовать

WeatherWidget.prototype = Object.create(Widget.prototype, {
  constructor: {value: WeatherWidget}
});

вместо этого. Это имеет дополнительное преимущество в том, что полученное свойство constructor не доступно для записи, перечислимо или настраивается.

Родительский конструктор вызывается только в том случае, если вы вызываете его явно, из WeatherWidget, например, с помощью

function WeatherWidget (…)
{
  Widget.apply(this, arguments);
}

См. также Function.prototype.extend() в моем JSX: object. js, чтобы обобщить это. Используя этот код, он станет

WeatherWidget.extend(Widget);

My Function.prototype.extend() принимает необязательный второй аргумент, с помощью которого вы можете легко увеличить прототип экземпляров WeatherWidget:

WeatherWidget.extend(Widget, {
  foo: 42,
  bar: "baz"
});

будет эквивалентно

WeatherWidget.extend(Widget);
WeatherWidget.prototype.foo = 42;
WeatherWidget.prototype.bar = "baz";

Вам все равно нужно вызвать родительский конструктор явно в дочернем конструкторе; эта часть не может быть автоматизирована. Но мой Function.prototype.extend() добавляет свойство _super к экземпляру Function, что упрощает его:

function WeatherWidget (…)
{
  WeatherWidget._super.apply(this, arguments);
}

Другие люди реализовали аналогичные расширения.

Ответ 2

В соответствии с некоторыми нечетными правилами Javascript new Widget фактически вызывает конструктор, а не возвращает ссылку на конструктор. Этот вопрос фактически отвечает на вопрос о различии между var a = new Widget() и var a = Widget().

Простыми словами ключевое слово new сообщает Javascript вызывать функцию Widget под другим набором правил, чем обычный вызов функции. Уходя с головы, я помню:

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

Без ключевого слова new вызов виджета будет

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

Ссылка: new ключевое слово

Ответ 3

WeatherWidget.prototype = new Widget;

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

Без ключевого слова new это будет назначение функции Widget для свойства prototype, что не имеет никакого смысла. Если вы добавите необязательные скобки (т.е. Widget()), он будет вызывать функцию нормально, но не как конструктор в новом экземпляре, а глобальный объект как контекст. См. Также ссылка для ключевого слова this.

Обратите внимание, что вы не должны действительно использовать этот код. Как сказано, он создает новый экземпляр, вызывая функцию конструктора. Но целью является создание только пустого объекта, который наследуется от объекта-прототипа Widget, а не для создания какого-либо экземпляра (что может нанести вред, в зависимости от кода). Вместо этого вы должны использовать Object.create (или его популярную прокладку):

WeatherWidget.prototype = Object.create(Widget.prototype);

см. также базовое наследование Javascript против прототипного наследования Crockford

Ответ 4

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

var Appendages = function(){
  this.legs = 2
};
var Features = function() {
   this.ears = 4;
   this.eyes = 1;
}

// Extend Features class with Appendages class.
Features.prototype = new Appendages;
var sara = new Features();
sara.legs;
// Returns 2.

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

var appendages = {
  legs : 2
};
var Features = function() {
   this.ears = 4;
   this.eyes = 1;
}

// Extend Features class with Appendages class.
Features.prototype = appendages;
var sara = new Features();
sara.legs;
// Returns 2.

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

var appendages = {
  legs : 2
};
var Features = function() {
   this.ears = 4;
   this.eyes = 1;
}

// Extend Features class with Appendages class.
Features.prototype = appendages;
var sara = new Features();
sara.legs;
// Returns 2.
appendages.hair = true;
sara.hair;
// Returns true.

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

var foo = {name : 'bob'};
var bar = {nachos : 'cheese'};
foo.prototype = bar;
foo.nachos;
// undefined

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

var foo = {name : 'bob'};
var bar = {nachos : 'cheese'};
foo.__proto__ = bar;
foo.nachos
// "cheese"

Читайте больше о понимании прототипов JavaScript здесь. Этот article из Pivotal Labs также очень хорош.

Ответ 5

new важно для наследования прототипов; т.е.
Создайте конструктор с помощью метода

var Obj = function(){};
Obj.prototype = {};
Obj.prototype.foo = function(){console.log('foo');};

Создайте второй конструктор для продолжения первого с помощью

var ExObj = function(){};

Теперь, если мы прототипируем без new,

ExObj.prototype = Obj;
(new ExObj).foo(); // TypeError: Object #<Object> has no method 'foo'

Это означает, что мы не унаследовали от прототипа Obj, однако, если прототип с new

ExObj.prototype = new Obj();
(new ExObj).foo(); // console logs 'foo'

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

Ответ 6

Функции JavaScript "МНОЖЕСТВО (2) ЛИЧНОСТИ"!!!

Они являются регулярными функциями с вводом и выводом, которые мы называем function().

Также они являются конструкторами JS-объектов, когда мы используем ключевое слово new. → > НО < < < новые созданные объекты НЕ ДОПУСКАЮТ конструкторов (например, объекты классов в наследовании на основе классов). Новые объекты - это экземпляры объекта свойства prototype конструктора.

Затем в WeatherWidget.prototype = вы помещаете объект, который вы хотите наследовать его свойства, к объектам, которые создаст конструктор, который обычно является new function(), а не функцией.

JavaScript создал HUGE путаницу в сообществе программирования, назвав объекты, созданные конструкторами, INSTANCES из них с ключевым словом instanceof.
> function f(){}
undefined
> new f() instanceof f
true