1869

JavaScriptのnewキーワードは、JavaScript はオブジェクト指向プログラミング言語ではないと人々が考える傾向があるため、最初に遭遇したときは非常に混乱する可能性があります。

  • それは何ですか?
  • どのような問題を解決しますか?
  • 適切な場合とそうでない場合はいつですか?
4

16 に答える 16

2237

次の 5 つのことを行います。

  1. 新しいオブジェクトを作成します。このオブジェクトの型は単にobjectです。
  2. この新しいオブジェクトの内部でアクセスできない[[prototype]] (つまり__proto__ ) プロパティを、コンストラクター関数の外部でアクセス可能なプロトタイプオブジェクトに設定します (すべての関数オブジェクトは自動的にプロトタイププロパティを持ちます)。
  3. 変数がthis新しく作成されたオブジェクトを指すようにします。
  4. thisが言及されるたびに、新しく作成されたオブジェクトを使用して、コンストラクター関数を実行します。
  5. nullコンストラクター関数が非オブジェクト参照を返さない限り、新しく作成されたオブジェクトを返します。この場合、そのオブジェクト参照が代わりに返されます。

注:コンストラクター関数newは、次のように、キーワードの後の関数を参照します。

new ConstructorFunction(arg1, arg2)

これが完了すると、新しいオブジェクトの未定義のプロパティが要求された場合、スクリプトはオブジェクトの[[prototype]]オブジェクトのプロパティを代わりにチェックします。これは、JavaScript の従来のクラス継承に似たものを取得する方法です。

これに関する最も難しい部分はポイント 2 です。すべてのオブジェクト (関数を含む) には、[[prototype]]と呼ばれる内部プロパティがあります。newObject.create、またはリテラル (関数はデフォルトで Function.prototype、数値は Number.prototype など) に基づいて、オブジェクトの作成時にのみ設定できます。Object.getPrototypeOf(someObject)でのみ読み取ることができます。この値を設定または読み取る他の方法はありません。

関数には、非表示の[[prototype]]プロパティに加えて、 prototypeと呼ばれるプロパティもあり、これにアクセスして変更することで、作成したオブジェクトに継承されたプロパティとメソッドを提供できます。


次に例を示します。

ObjMaker = function() {this.a = 'first';};
// ObjMaker is just a function, there's nothing special about it that makes 
// it a constructor.

ObjMaker.prototype.b = 'second';
// like all functions, ObjMaker has an accessible prototype property that 
// we can alter. I just added a property called 'b' to it. Like 
// all objects, ObjMaker also has an inaccessible [[prototype]] property
// that we can't do anything with

obj1 = new ObjMaker();
// 3 things just happened.
// A new, empty object was created called obj1.  At first obj1 was the same
// as {}. The [[prototype]] property of obj1 was then set to the current
// object value of the ObjMaker.prototype (if ObjMaker.prototype is later
// assigned a new object value, obj1's [[prototype]] will not change, but you
// can alter the properties of ObjMaker.prototype to add to both the
// prototype and [[prototype]]). The ObjMaker function was executed, with
// obj1 in place of this... so obj1.a was set to 'first'.

obj1.a;
// returns 'first'
obj1.b;
// obj1 doesn't have a property called 'b', so JavaScript checks 
// its [[prototype]]. Its [[prototype]] is the same as ObjMaker.prototype
// ObjMaker.prototype has a property called 'b' with value 'second'
// returns 'second'

これは、クラスの継承に似ています。これを使用して作成したオブジェクトはnew ObjMaker()、'b' プロパティも継承しているように見えるからです。

サブクラスのようなものが必要な場合は、次のようにします。

SubObjMaker = function () {};
SubObjMaker.prototype = new ObjMaker(); // note: this pattern is deprecated!
// Because we used 'new', the [[prototype]] property of SubObjMaker.prototype
// is now set to the object value of ObjMaker.prototype.
// The modern way to do this is with Object.create(), which was added in ECMAScript 5:
// SubObjMaker.prototype = Object.create(ObjMaker.prototype);

SubObjMaker.prototype.c = 'third';  
obj2 = new SubObjMaker();
// [[prototype]] property of obj2 is now set to SubObjMaker.prototype
// Remember that the [[prototype]] property of SubObjMaker.prototype
// is ObjMaker.prototype. So now obj2 has a prototype chain!
// obj2 ---> SubObjMaker.prototype ---> ObjMaker.prototype

obj2.c;
// returns 'third', from SubObjMaker.prototype

obj2.b;
// returns 'second', from ObjMaker.prototype

obj2.a;
// returns 'first', from SubObjMaker.prototype, because SubObjMaker.prototype 
// was created with the ObjMaker function, which assigned a for us

私は最終的にこのページを見つける前に、このテーマに関する大量のごみを読みました.

于 2010-09-07T12:30:58.123 に答える
436

次の関数があるとします。

var Foo = function(){
  this.A = 1;
  this.B = 2;
};

これを次のようにスタンドアロン関数として呼び出す場合:

Foo();

windowこの関数を実行すると、オブジェクトに 2 つのプロパティ (Aと)が追加されますB。そのように実行すると、それは関数を呼び出したオブジェクトであり、関数内は関数を呼び出したオブジェクトであるwindowため、に追加されます。少なくともJavascriptでは。windowthis

次に、次のように呼び出しますnew

var bar = new Foo();

関数呼び出しに を追加newすると、新しいオブジェクトが作成され (単にvar bar = new Object()) this、関数内の が、関数を呼び出したオブジェクトではなく、作成したばかりの新しいオブジェクトを指しObjectます。プロパティとbarを持つオブジェクトも同様です。どの関数もコンストラクターになることができますが、常に意味があるとは限りません。AB

于 2009-10-29T22:22:15.150 に答える
130

初心者がよりよく理解できるように

ブラウザ コンソールで次のコードを試してください。

function Foo() { 
    return this; 
}

var a = Foo();       //returns window object
var b = new Foo();   //returns empty object of foo

a instanceof Window;  // true
a instanceof Foo;     // false

b instanceof Window;  // false
b instanceof Foo;     // true

これで、コミュニティ wiki の回答を読むことができます:)

于 2015-05-27T09:23:53.560 に答える
39

したがって、おそらくオブジェクトのインスタンスを作成するためのものではありません

まさにそのために使われています。次のように関数コンストラクターを定義します。

function Person(name) {
    this.name = name;
}

var john = new Person('John');

ただし、ECMAScript の追加の利点は、.prototypeプロパティを使用して拡張できることです。そのため、次のようなことができます...

Person.prototype.getName = function() { return this.name; }

このコンストラクターから作成されたすべてのオブジェクトは、getNameアクセスできるプロトタイプ チェーンにより、 を持ちます。

于 2009-10-29T21:34:36.350 に答える
29

JavaScriptオブジェクト指向のプログラミング言語であり、まさにインスタンスの作成に使用されます。クラスベースではなくプロトタイプベースですが、それはオブジェクト指向ではないという意味ではありません。

于 2009-10-29T21:36:51.950 に答える
17

すでにいくつかの非常に優れた回答がありますが、関数に明示的な return ステートメントがある場合に何が起こるかについて、以下のケースIIIに関する私の観察を強調するために新しい回答を投稿していますnew。以下のケースをご覧ください。

ケース I :

var Foo = function(){
  this.A = 1; 
  this.B = 2;
};
console.log(Foo()); //prints undefined
console.log(window.A); //prints 1

上記は、 が指す無名関数を呼び出す単純なケースですFoo。この関数を呼び出すと、 が返されますundefined。明示的な return ステートメントがないため、JavaScript インタープリターは強制的にreturn undefined;ステートメントを関数の最後に挿入します。thisここで window は、新しいプロパティAとプロパティを取得する呼び出しオブジェクト (contextual )Bです。

ケース II :

var Foo = function(){
  this.A = 1;
  this.B = 2;
};
var bar = new Foo();
console.log(bar()); //illegal isn't pointing to a function but an object
console.log(bar.A); //prints 1

ここで、JavaScript インタープリターはキーワードを認識して、が指す無名関数newの呼び出しオブジェクト (contextual ) として機能する新しいオブジェクトを作成します。この場合、(window オブジェクトの代わりに) 新しく作成されたオブジェクトのプロパティになります。明示的な return ステートメントがないため、JavaScript インタープリターは return ステートメントを強制的に挿入して、キーワードの使用により作成された新しいオブジェクトを返します。thisFooABnew

ケース III :

var Foo = function(){
  this.A = 1;
  this.B = 2;
  return {C:20,D:30}; 
};
var bar = new Foo();
console.log(bar.C);//prints 20
console.log(bar.A); //prints undefined. bar is not pointing to the object which got created due to new keyword.

ここでもキーワードを認識する JavaScript インタープリターは、が指す無名関数newの呼び出しオブジェクト (contextual ) として機能する新しいオブジェクトを作成します。再び、新しく作成されたオブジェクトのプロパティになります。しかし、今回は明示的な return ステートメントがあるため、JavaScript インタープリターはそれ自体では何もしません。thisFooAB

ケースIIIで注意すべきことは、キーワードによって作成されたオブジェクトがnewレーダーから失われたことです。実際には、JavaScript インタープリターがキーワードbarのために作成したものではない、まったく別のオブジェクトを指しています。new

JavaScripit から David Flanagan を引用: The Definitive Guide (第 6 版)、Ch. 4、ページ番号 62:

オブジェクト作成式が評価されると、JavaScript は、オブジェクト初期化子 {} によって作成されるオブジェクトと同様に、最初に新しい空のオブジェクトを作成します。次に、指定された引数で指定された関数を呼び出し、新しいオブジェクトを this キーワードの値として渡します。関数はこれを使用して、新しく作成されたオブジェクトのプロパティを初期化できます。コンストラクターとして使用するために作成された関数は値を返さず、オブジェクト作成式の値は新しく作成され初期化されたオブジェクトです。コンストラクターがオブジェクト値を返す場合、その値はオブジェクト作成式の値になり、新しく作成されたオブジェクトは破棄されます。

---追加情報---

上記のケースのコード スニペットで使用される関数には、JS の世界では次のような特別な名前があります。

ケース I および II - コンストラクター関数

ケース III - ファクトリ関数。ファクトリ関数は、現在のスレッドで概念を説明するために行ったキーワードでは使用しないでください。new

このスレッドでそれらの違いについて読むことができます。

于 2017-10-05T02:28:26.533 に答える
14

Javascript は、オブジェクト指向プログラミング パラダイムをサポートする動的プログラミング言語であり、オブジェクトの新しいインスタンスの作成に使用されます。

オブジェクトにはクラスは必要ありません。Javascript はプロトタイプ ベースの言語です。

于 2009-10-29T21:37:07.170 に答える
7

コードは言葉よりも簡単な場合があります。

var func1 = function (x) { this.x = x; }                    // used with 'new' only
var func2 = function (x) { var z={}; z.x = x; return z; }   // used both ways
func1.prototype.y = 11;
func2.prototype.y = 12;

A1 = new func1(1);      // has A1.x  AND  A1.y
A2 =     func1(1);      // undefined ('this' refers to 'window')
B1 = new func2(2);      // has B1.x  ONLY
B2 =     func2(2);      // has B2.x  ONLY

私にとっては、プロトタイプを作成しない限り、func2 のスタイルを使用します。これにより、関数の内外でもう少し柔軟性が得られるからです。

于 2015-05-16T07:21:57.490 に答える
3

newキーワードは、新しいオブジェクト インスタンスを作成するためのものです。はい、javascript はオブジェクト指向プログラミング パラダイムをサポートする動的プログラミング言語です。オブジェクトの命名規則は、 new キーワードによってインスタンス化されるオブジェクトには常に大文字を使用することです。

obj = new Element();
于 2009-10-29T21:38:25.597 に答える
2

このnewキーワードは、関数をコンストラクターとして使用してオブジェクトのインスタンスを作成します。例えば:

var Foo = function() {};
Foo.prototype.bar = 'bar';

var foo = new Foo();
foo instanceof Foo; // true

インスタンスprototypeは、コンストラクター関数の を継承します。したがって、上記の例を考えると...

foo.bar; // 'bar'
于 2009-10-29T21:37:40.093 に答える
2

JavaScript per si は、常に元の仕様の EcmaScript の実装であるため、プラットフォームごとに大きく異なる可能性があります。

いずれにせよ、実装とは無関係に、EcmaScript 仕様の権利に従うすべての JavaScript 実装は、オブジェクト指向言語を提供します。ES 規格によると:

ECMAScript は、ホスト環境内で計算を実行し、計算オブジェクトを操作するためのオブジェクト指向プログラミング言語です。

これで、JavaScript は EcmaScript の実装であり、したがってオブジェクト指向言語であることに同意しました。newオブジェクト指向言語の操作の定義では、そのようなキーワードを使用して、特定の型 (C# などの場合は匿名型を含む) のクラスからオブジェクト インスタンスを作成すると述べています。

仕様から読み取れるように、EcmaScript ではクラスを使用しません。

ECMAScript は、C++、Smalltalk、Java などのクラスを使用しません。代わりに、オブジェクトは、リテラル表記や、オブジェクトを作成し、プロパティに初期値を割り当てることによってオブジェクトのすべてまたは一部を初期化するコードを実行するコンストラクターなど、さまざまな方法で作成できます。各コンストラクターは、プロトタイプ ベースの継承と共有プロパティを実装するために使用される "prototype" という名前のプロパティを持つ関数です。オブジェクトは
、新しい式でコンストラクターを使用して作成されます。たとえば、new Date(2009,11) は新しい Date オブジェクトを作成します。new を使用せずにコンストラクターを呼び出すと、コンストラクターに依存する結果が生じます。たとえば、Date() は、オブジェクトではなく、現在の日付と時刻の文字列表現を生成します。

于 2015-05-13T23:05:28.037 に答える