在Derived.prototype = new Base使用'new'关键字的原因是什么

Kai*_*Kai 50 javascript constructor prototype

以下代码的作用如下:

WeatherWidget.prototype = new Widget;
Run Code Online (Sandbox Code Playgroud)

哪里Widget是构造函数,我想用新函数扩展Widget'类' WeatherWidget.

什么是new关键字在那里做什么以及如果被遗漏会发生什么?

Poi*_*ars 51

WeatherWidget.prototype = new Widget;
Run Code Online (Sandbox Code Playgroud)

new关键字调用Widget构造函数,返回值分配给prototype属性.(如果你省略new,Widget除非你添加了一个参数列表,否则你不会调用().但是,调用Widget这种方式可能是不可能的.如果它不是严格模式代码并且实现是实现的,它肯定有可能破坏全局命名空间.符合ECMAScript Ed.5.x那里,因为this在构造函数中会引用ECMAScript的全局对象.)

但是这种方法实际上来自旧的Netscape JavaScript 1.3指南中的一个非常病毒的 坏例子(在Oracle,以前的Sun镜像).

这样,您的WeatherWidget实例将全部继承自同一 Widget实例.原型链将是:

[new WeatherWidget()] ? [new Widget()] ? [Widget.prototype] ? …
Run Code Online (Sandbox Code Playgroud)

这可能很有用,但大多数时候你不希望它发生.除非您希望所有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;
Run Code Online (Sandbox Code Playgroud)

constructor原型属性应该是固定的为好,这样你的WeatherWidget情况下,w将有w.constructor === WeatherWidget预期,而不是w.constructor === Widget.但是,请注意,之后可以枚举.

这样一来,WeatherWidget情况将通过继承原型链的属性,但它们之间不会分享的属性值,因为它们继承Widget.prototype,通过Dummy它没有自己的属性:

[new WeatherWidget()] ? [new Dummy()] ? [Widget.prototype] ? …
Run Code Online (Sandbox Code Playgroud)

在ECMAScript Ed的实现中.5及以后,你可以而且应该使用

WeatherWidget.prototype = Object.create(Widget.prototype, {
  constructor: {value: WeatherWidget}
});
Run Code Online (Sandbox Code Playgroud)

代替.这具有额外的优点,即所得constructor属性不可写,可枚举或可配置.

只有在显式调用父构造函数时,才会调用父构造函数WeatherWidget,例如

function WeatherWidget (…)
{
  Widget.apply(this, arguments);
}
Run Code Online (Sandbox Code Playgroud)

另请参阅Function.prototype.extend()我的JSX:object.js,了解如何概括它.使用该代码,它将成为

WeatherWidget.extend(Widget);
Run Code Online (Sandbox Code Playgroud)

Function.prototype.extend()需要一个可选的第二个参数,您可以使用它轻松扩充WeatherWidget实例的原型:

WeatherWidget.extend(Widget, {
  foo: 42,
  bar: "baz"
});
Run Code Online (Sandbox Code Playgroud)

相当于

WeatherWidget.extend(Widget);
WeatherWidget.prototype.foo = 42;
WeatherWidget.prototype.bar = "baz";
Run Code Online (Sandbox Code Playgroud)

但是,您仍然需要在子构造函数中显式调用父构造函数; 那部分不能合理地自动化.但我为实例Function.prototype.extend()添加了一个_super属性Function,使其更容易:

function WeatherWidget (…)
{
  WeatherWidget._super.apply(this, arguments);
}
Run Code Online (Sandbox Code Playgroud)

其他人已实施类似的扩展.

  • +1鄙视坏方法,-1不提'Object.create` :-) (4认同)

Jer*_*her 7

根据一些奇怪的Javascript规则,new Widget实际上调用构造函数而不是返回对构造函数的引用.这个问题实际上回答了var a = new Widget()和之间的区别var a = Widget().

简单来说,new关键字告诉Javascript Widget在一组不同于常规函数调用的规则下调用函数.脱离我的头脑,我记得的是:

  1. 创建了一个全新的对象
  2. Widget可以使用this关键字来引用该对象.
  3. 如果Widget不返回任何内容,则将创建此新对象.
  4. 此对象将继承一些其他属性,这些属性将指示它是Widget用于跟踪属性链的.

如果没有new关键字,则会调用窗口小部件

  1. 如果在严格模式下,this将设置为undefined.
  2. 否则,this将引用全局对象.(window由浏览器调用.)
  3. 如果函数没有返回任何内容,则undefined返回.

参考: new关键字

  • @Bergi - 在Javascript构造函数中,parens是可选的,因为某些原因我从未想过.[见这个讨论](http://stackoverflow.com/questions/6439290/parentheses-after-new-function-optional) (2认同)

Ber*_*rgi 5

WeatherWidget.prototype = new Widget;
Run Code Online (Sandbox Code Playgroud)

确实创建了Widget构造函数的新实例并将其用作WeatherWidget原型对象.使用new关键字创建新对象,设置它的继承链Widget.prototype,并在其上应用构造函数(您可以在其中设置单个属性的'n'方法,或创建私有范围的变量).

没有new关键字,它将是Widgetprototype属性的函数赋值- 这没有任何意义.如果你要添加可选括号(ie Widget()),它会正常调用函数,但不能作为新实例的构造函数,而是将全局对象作为上下文.另请参阅关键字参考this.

请注意,您不应该真正使用此代码.如上所述,它通过调用构造函数创建一个新实例.但目的只是创建一个从s原型对象继承的对象Widget,而不是实例化某些东西(这可能会造成一些伤害,具体取决于代码).相反,你应该使用Object.create(或其流行的垫片):

WeatherWidget.prototype = Object.create(Widget.prototype);
Run Code Online (Sandbox Code Playgroud)

另见Javascript基本继承与Crockford原型继承