以下代码有什么作用:
WeatherWidget.prototype = new Widget;
whereWidget
是一个构造函数,我想用一个新函数来扩展 Widget 'class' WeatherWidget
。
关键字在那里做什么new
,如果它被遗漏会发生什么?
以下代码有什么作用:
WeatherWidget.prototype = new Widget;
whereWidget
是一个构造函数,我想用一个新函数来扩展 Widget 'class' WeatherWidget
。
关键字在那里做什么new
,如果它被遗漏会发生什么?
WeatherWidget.prototype = new Widget;
new
关键字Widget
作为构造函数调用,并将返回值分配给属性prototype
。(如果省略,除非添加参数列表,否则new
不会调用。但是,以这种方式调用可能是不可能的。如果它不是严格模式代码并且实现是,它肯定有可能破坏全局命名空间那里符合 ECMAScript Ed. 5.x,因为 then在构造函数中将引用 ECMAScript 的全局对象。)Widget
()
Widget
this
但这种方法实际上来自旧的 Netscape JavaScript 1.3 指南(反映在 Oracle,以前的 Sun)中的一个非常 糟糕的例子。
这样,您的WeatherWidget
实例都将继承自同一个 Widget
实例。原型链将是:
[new WeatherWidget()] → [new Widget()] → [Widget.prototype] → …
这可能很有用,但大多数时候您不希望它发生。您不应该在此处这样做,除非您希望所有WeatherWidget
实例在它们之间共享它们从该实例继承的属性值Widget
,并且只能通过它,从Widget.prototype
. 另一个问题是您需要以这种方式调用父构造函数,这可能不允许像您那样在没有参数的情况下调用,或者无法正确初始化。它当然与模拟基于类的继承毫无关系,例如从 Java 中。
在这些基于原型的语言中实现基于类的继承的正确方法是(最初由Lasse Reichstein Nielsencomp.lang.javascript
在 2003 年设计,用于克隆对象):
function Dummy () {}
Dummy.prototype = Widget.prototype;
WeatherWidget.prototype = new Dummy();
WeatherWidget.prototype.constructor = WeatherWidget;
原型属性也应该是固定的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
例如from
function WeatherWidget (…)
{
Widget.apply(this, arguments);
}
另请参阅Function.prototype.extend()
我的JSX:object.js以了解如何概括这一点。使用该代码,它将变成
WeatherWidget.extend(Widget);
MyFunction.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);
}
其他人已经实现了类似的扩展。
根据一些奇怪的 Javascript 规则,new Widget
实际上是调用构造函数而不是返回对构造函数的引用。var a = new Widget()
这个问题实际上回答了和之间的区别的问题var a = Widget()
。
简单来说,new
关键字告诉 Javascript 在与Widget
常规函数调用不同的规则集下调用函数。在我脑海中浮现,我记得的是:
Widget
可以使用this
关键字来引用该对象。Widget
不返回任何内容,则将创建此新对象。Widget
用于跟踪属性链的创建的。如果没有new
关键字,对小部件的调用将
this
将设置为undefined.
this
将引用全局对象。window
(由浏览器调用。)undefined
将被返回。参考:
new
关键词
WeatherWidget.prototype = new Widget;
确实创建了Widget
构造函数的一个新实例并将其用作WeatherWidget
的原型对象。使用new
关键字创建新对象,将其继承链设置为Widget.prototype
,并在其上应用构造函数(您可以在其中设置单独的属性'n'方法,或创建私有范围的变量)。
如果没有new
关键字,它将是将Widget
函数分配给prototype
属性 - 这没有任何意义。如果您添加可选的括号(即Widget()
),它将正常调用该函数,但不是作为新实例的构造函数,而是将全局对象作为上下文。另请参阅关键字的参考this
。
请注意,您不应该真正使用此代码。如前所述,它通过调用构造函数创建一个新实例。但目的只是创建一个从 s 原型对象继承的空Widget
对象,而不是实例化某些东西(这可能会造成一些伤害,具体取决于代码)。相反,您应该使用Object.create
(或其流行的 shim):
WeatherWidget.prototype = Object.create(Widget.prototype);
用简单的英语来说,你正在用另一个类扩展一个类。原型只能是一个对象,因此您将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"
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
.
JavaScript 函数是“MULTIPLE(2) PERSONALITIES”!!!
它们是具有输入和输出的常规函数,我们称之为function()
.
new
当我们使用关键字时,它们也是 JS 对象的构造函数。>>>BUT<<< 新创建的对象不是构造函数的实例(如基于类的继承中的类对象)。新对象是prototype
构造函数属性对象的实例。
然后WeatherWidget.prototype =
将要继承其属性的对象放入构造函数将创建的对象中,这通常是new function()
而不是函数。
instanceof
JavaScript 通过使用关键字命名构造函数创建的对象,它们的实例,在编程社区中造成了巨大的混乱。
> function f(){}
undefined
> new f() instanceof f
true