在Derived.prototype = new Base中使用“new”关键字的原因是什么?

下面的代码是做什么的:

WeatherWidget.prototype = new Widget; 

其中Widget是一个构造函数,我想用一个新的函数WeatherWidget扩展Widget的“类”。

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

 WeatherWidget.prototype = new Widget; 

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

但是这种方法实际上来自于旧版Netscape JavaScript 1.3指南 (甲骨文,以前称为Sun)中的一个病毒 坏例子

这样,您的WeatherWidget实例将全部从相同的 Widget实例inheritance。 原型链将是:

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

这可能是有用的,但大多数时候你不希望它发生。 除非您希望所有WeatherWidget实例在其中共享从它们inheritance的Widget实例的属性值 ,并且只能通过它Widget.prototype 共享,否则不应在此处执行此Widget.prototype 。 另一个问题是你需要这样调用父构造函数,这样可能不允许在没有参数的情况下调用,或者不能正确初始化。 它与模拟基于类的inheritance无关,例如从Java中已知。

在这些基于原型的语言中实现基于类的inheritance的正确方法是(最初由Lasse Reichstein Nielsen在2003年的comp.lang.javascript中为了克隆对象而devise ):

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

constructor prototype属性也应该被修正,这样你的w.constructor === WeatherWidget实例将会像预期的那样拥有w.constructor === WeatherWidget ,而不是w.constructor === Widget 。但是请注意,它之后是可枚举的)。

这样, WeatherWidget实例将通过原型链inheritance属性,但不会共享属性值,因为它们通过DummyWidget.prototypeinheritance,而Dummy没有自己的属性:

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

父构造函数只有在你明确地调用它的时候才会被调用,例如WeatherWidget

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

(如果您处于一个非常有限的环境中,要求遵从ECMAScript Ed.5及更高版本 – 不要在Web上 – 或者ECMAScript Edition 5.1的实现已经无处不在 – 从现在起10年左右, 3那么长,你可以而且应该使用(Widget.prototype, {constructor: {value: WeatherWidget}}); WeatherWidget.prototype = Object.create (Widget.prototype, {constructor: {value: WeatherWidget}});相反,它具有额外的优点,即得到的constructor属性不可写,可枚举或可configuration的 。)

另请参阅我的JSX:object.js中的 Function.prototype.extend()以了解如何对其进行概括。 使用该代码,它会成为

 WeatherWidget.extend(Widget); 

我的Function.prototype.extend()采用可选的第二个参数,您可以轻松地增加WeatherWidget实例的原型:

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

将相当于

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

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

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

其他人已经实施了类似的扩展。

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

简单地说, new关键字告诉Javascript在不同于普通函数调用的一组规则下调用函数Widget 。 离开我的头顶,我记得的是:

  1. 有一个全新的对象创build
  2. Widget可以使用this关键字来引用该对象。
  3. 如果Widget不返回任何东西,这个新的对象将被创build。
  4. 该对象将inheritance一些附加属性,这些属性将指示它是由Widget创build的,用于追踪属性链。

没有new关键字,调用widget会

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

参考: new关键字

 WeatherWidget.prototype = new Widget; 

不会创buildWidget构造函数的新实例,并将其用作WeatherWidget的原型对象。 使用new关键字创build新对象,将其inheritance链设置为Widget.prototype ,并在其上应用构造函数(您可以在其中设置各个属性的n方法或创build专用范围的variables)。

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

注意你不应该使用这个代码。 如上所述,它通过调用构造函数来创build一个新的实例。 但目的只是创build一个从Widget的原型对象inheritance的对象,而不是实例化一些东西(这可能会造成一些伤害,取决于代码)。 相反,你应该使用Object.create (或其stream行的垫片 ):

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

另请参阅Javascript基本inheritance与Crockford原型inheritance

用简单的英语,你正在扩大一个class级。 一个原型只能是一个对象,所以你把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. 

请注意,这一切都发生在实例化过程中,这意味着您不能在创build对象之后切换原型:

 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原型的信息 。 这篇来自Pivotal Labs的文章也非常好。

new原型inheritance是重要的; 即
用一个方法创build一个构造函数

 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的原型inheritance,但是,如果我们用new原型

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

而且,向ExObj的原型添加新的东西并不会对其基础Obj进行任何更改。

JavaScript的function是“多(2)个人”!

它们是具有input和输出的正则函数,我们称之为function()

当我们使用new关键字时,它们也是JS对象的构造函数。 >>> BUT <<<新创build的对象不是构造函数的实例(就像基于类的inheritance中的类对象)。 新对象是构造函数prototype属性对象的实例。

然后在WeatherWidget.prototype =你把你想要inheritance它的属性的对象的构造函数将创build的对象,这通常是new function()而不是一个函数。

JavaScript在编程社区中造成了巨大的混乱,通过命名由构造函数创build的对象,使用instanceof关键字指定它们的INSTANCES。
> function f(){}
undefined
> new f() instanceof f
true