50

次のコードは何をしますか:

WeatherWidget.prototype = new Widget;

whereWidgetはコンストラクターで、Widget の「クラス」を新しい関数で拡張したいと考えていますWeatherWidget

キーワードはそこで何をしnewており、それが省略された場合はどうなりますか?

4

6 に答える 6

51
WeatherWidget.prototype = new Widget;

newキーワードがコンストラクターとして呼び出され、Widget戻り値がプロパティに割り当てられprototypeます。( を省略すると、引数リスト を追加しない限りnew呼び出されません。ただし、その方法で呼び出すことはできない可能性があります。厳格モードのコードではなく、実装がそこでは ECMAScript Ed. 5.x に準拠します。これは、コンストラクターで ECMAScript のグローバル オブジェクトを参照するためです。)Widget()Widgetthis

しかし、このアプローチは実際には、古い Netscape JavaScript 1.3 ガイド(以前の Sun である Oracle にミラーリングされています)の非常にバイラル な悪い例から来ています。

このようにして、インスタンスはすべて同じWeatherWidgetインスタンスから継承されます。プロトタイプ チェーンは次のようになります。 Widget

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

これは便利ですが、ほとんどの場合、これが発生することは望ましくありません。すべてのWeatherWidgetインスタンスが、このインスタンスから継承するプロパティ値を共有する場合を除き、ここでそれを行うべきではありませ。もう 1 つの問題は、この方法で親コンストラクターを呼び出す必要があることです。この方法では、引数なしで呼び出すことができないか、適切に初期化されない可能性があります。これは、Java などで知られているクラスベースの継承のエミュレーションとはまったく関係ありません。WidgetWidget.prototype

これらのプロトタイプベースの言語でクラスベースの継承を実装する適切な方法は次のとおりです (もともとは、2003 年にラッセ ライヒシュタイン ニールセンがcomp.lang.javascriptオブジェクトの複製のために考案したものです)。

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

constructorプロトタイプ プロパティも修正する必要がありWeatherWidgetます。ただし、後で列挙可能であることに注意してください。ww.constructor === WeatherWidgetw.constructor === Widget

このように、インスタンスはプロトタイプ チェーンを介しWeatherWidgetてプロパティを継承しますが、独自のプロパティを持たないから継承するため、インスタンス間でプロパティ値を共有しません。Widget.prototypeDummy

[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);

Myは、インスタンスFunction.prototype.extend()のプロトタイプを簡単に拡張できるオプションの 2 番目の引数を取ります。WeatherWidget

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

と同等です

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

ただし、子コンストラクターで明示的に親コンストラクターを呼び出す必要があります。その部分は合理的に自動化できません。しかし、インスタンスにプロパティをFunction.prototype.extend()追加すると、簡単になります。_superFunction

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

他の人も同様の拡張機能を実装しています。

于 2012-09-26T01:15:55.723 に答える
7

いくつかの奇妙な Javascript 規則に従って、new Widgetコンストラクターへの参照を返すのではなく、実際にコンストラクターを呼び出します。var a = new Widget()この質問は、実際にはとの違いに関する質問に答えますvar a = Widget()

簡単に言えば、キーワードは、通常の関数呼び出しとは異なる規則セットの下でnew関数を呼び出すように Javascript に指示します。Widget頭のてっぺんから外れて、私が覚えているのは次のとおりです。

  1. 作成された真新しいオブジェクトがあります
  2. Widgetthisキーワードを使用して、そのオブジェクトを参照できます。
  3. Widget何も返さない場合、この新しいオブジェクトが作成されます。
  4. Widgetこのオブジェクトは、プロパティ チェーンを追跡するために使用される、によって作成されたことを示すいくつかの追加プロパティを継承します。

キーワードがないnewと、ウィジェットへの呼び出しは

  1. 厳密モードの場合は、thisに設定されますundefined.
  2. それ以外の場合はthis、グローバル オブジェクトを参照します。(ブラウザによって呼び出さwindowれます。)
  3. 関数が何も返さない場合は、undefinedが返されます。

参考: newキーワード

于 2012-09-26T00:22:10.303 に答える
5
WeatherWidget.prototype = new Widget;

Widgetコンストラクターの新しいインスタンスを作成し、それをWeatherWidgetのプロトタイプ オブジェクトとして使用します。newキーワードを使用して新しいオブジェクトを作成し、その継承チェーンを にセットアップしWidget.prototype、コンストラクター関数を適用します (ここで、個々のプロパティのメソッドをセットアップするか、プライベート スコープの変数を作成できます)。

newキーワードがなければWidget、プロパティへの関数の割り当てになりprototypeます - これは意味がありません。オプションの括弧 (つまりWidget()) を追加すると、関数が通常どおり呼び出されますが、新しいインスタンスのコンストラクターとしてではなく、グローバル オブジェクトをコンテキストとして呼び出します。キーワードのリファレンスthisも参照してください。

このコードは実際には使用しないでください。前述のように、コンストラクター関数を呼び出して新しいインスタンスを作成します。ただし、目的はs プロトタイプ オブジェクトから継承する空のWidgetオブジェクトを作成することだけであり、何かをインスタンス化することではありません (コードによっては、何らかの害を及ぼす可能性があります)。代わりに、Object.create(またはその人気のある shim)を使用する必要があります。

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

Javascript の基本的な継承と Crockford のプロトタイプの継承も参照してください。

于 2012-09-26T00:38:56.927 に答える
3

平易な英語では、あるクラスを別のクラスに拡張しています。プロトタイプはオブジェクトにしかできないため、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 プロトタイプの理解について詳しくは、こちらをご覧ください。Pivotal Labs のこの記事も非常に優れています。

于 2012-09-26T00:40:30.343 に答える
2

new プロトタイプの継承にとって重要です。つまり
、メソッドでコンストラクターを作成します

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

最初のコンストラクターを拡張する 2 番目のコンストラクターを作成します。

var ExObj = function(){};

ここで、 なしでプロトタイプを作成するnewと、

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

これは、 のプロトタイプから継承していないことを意味しますがObjnew

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

さらに、 のプロトタイプに新しいものを追加しても、そのExObjベースであるObj.

于 2012-09-26T00:32:22.433 に答える
0

JavaScript 関数は "MULTIPLE(2) PERSONALITIES" です!!!

それらは入力と出力を持つ通常の関数であり、 のように呼び出しますfunction()

newまた、キーワードを使用すると、JS オブジェクトのコンストラクターになります。>>>しかし<<< 新しく作成されたオブジェクトは、コンストラクターのインスタンスではありません (クラスベースの継承におけるクラスのオブジェクトのように)。prototype新しいオブジェクトは、コンストラクターのプロパティのオブジェクトのインスタンスです。

次にWeatherWidget.prototype =、コンストラクターが作成するオブジェクトにプロパティを継承するオブジェクトを配置します。これは通常new function()、関数ではなく関数です。

JavaScript は、コンストラクターによって作成されたオブジェクトの名前をinstanceofキーワードでインスタンス化することにより、プログラミング コミュニティに大きな混乱を引き起こしました。
> function f(){}
undefined
> new f() instanceof f
true

于 2014-09-13T18:23:43.613 に答える