new
JavaScript のキーワードは、JavaScriptはオブジェクト指向プログラミング言語ではないと考える傾向があるため、最初に出会ったときは非常に混乱する可能性があります。
- それは何ですか?
- それはどのような問題を解決しますか?
- いつそれが適切でいつ適切でないのですか?
new
JavaScript のキーワードは、JavaScriptはオブジェクト指向プログラミング言語ではないと考える傾向があるため、最初に出会ったときは非常に混乱する可能性があります。
回答:
5つのことを行います。
this
新しく作成されたオブジェクトに変数のポイントを。this
言及された場合は常に、新しく作成されたオブジェクトを使用して、コンストラクター関数を実行します。null
オブジェクト参照を返さない限り、新しく作成されたオブジェクトを返します。この場合、そのオブジェクト参照が代わりに返されます。注:コンストラクター関数は、次のように、new
キーワードの後の関数を参照します。
new ConstructorFunction(arg1, arg2)
これが完了すると、新しいオブジェクトの未定義のプロパティが要求された場合、スクリプトは代わりにオブジェクトの[[prototype]]オブジェクトのプロパティをチェックします。これにより、JavaScriptの従来のクラス継承に似たものが得られます。
これについて最も難しい部分はポイント番号2です。すべてのオブジェクト(関数を含む)には、[[prototype]]と呼ばれるこの内部プロパティがあります。それはできる唯一のいずれかで、オブジェクトの作成時に設定される新しいと、Object.create、またはリテラル(Function.prototypeへの機能のデフォルトなどNumber.prototypeを、までの数字)に基づきます。Object.getPrototypeOf(someObject)でのみ読み取ることができます。この値を設定または読み取る他の方法はありません。
関数には、非表示の[[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
私は最終的にこのページを見つける前に、この主題について大量のゴミを読みました。このページは、素晴らしい図で非常によく説明されています。
ObjMaker
値を返す関数として定義されている場合、何が違うのですか?
new
が存在するため、関数/オブジェクトを構築/コピーするためにファクトリメソッドを記述する必要はありません。これは、「これをコピーして、親の「クラス」のようにすること、効率的かつ正確に実行すること、そして私、JSのみが内部でアクセスできる継承情報を保存すること」を意味します。これを行うにprototype
は、新しいオブジェクトのアクセスできない内部オブジェクトを変更して、継承されたメンバーを不透明にカプセル化し、従来のOO継承チェーン(ランタイムで変更できない)を模倣します。なしnew
でこれをシミュレートできますが、継承はランタイムで変更可能になります。良い?悪い?あなた次第。
Notice that this pattern is deprecated!
。クラスのプロトタイプを設定するための正しい最新のパターンは何ですか?
次の関数があるとします。
var Foo = function(){
this.A = 1;
this.B = 2;
};
これをスタンドアロン関数として呼び出すと、次のようになります。
Foo();
この関数を実行すると、window
オブジェクトに2つのプロパティが追加されます(A
およびB
)。そのように実行したときに関数を呼び出したオブジェクトであり、関数内では関数を呼び出したオブジェクトであるwindow
ため、それを追加します。少なくともJavaScriptでは。window
this
さて、これをnew
次のように呼び出します:
var bar = new Foo();
new
関数呼び出しに追加すると、新しいオブジェクトが作成され(ちょうどvar bar = new Object()
)this
、関数内が、関数Object
を呼び出したオブジェクトではなく、作成したばかりの新しいオブジェクトを指すようになります。これbar
で、プロパティA
とを持つオブジェクトになりますB
。どの関数もコンストラクターにすることができますが、常に意味があるわけではありません。
window
暗黙的にメソッドになります。閉鎖の場合でも、匿名の場合でも。ただし、この例では、ウィンドウでの単純なメソッド呼び出しです:Foo();
=> [default context].Foo();
=> window.Foo();
。この式にwindow
はコンテキストがあります(重要なのは発信者だけではありません)。
ダニエルハワードの回答に加えて、ここで何をするかnew
(少なくともそうするようです):
function New(func) {
var res = {};
if (func.prototype !== null) {
res.__proto__ = func.prototype;
}
var ret = func.apply(res, Array.prototype.slice.call(arguments, 1));
if ((typeof ret === "object" || typeof ret === "function") && ret !== null) {
return ret;
}
return res;
}
ながら
var obj = New(A, 1, 2);
に相当
var obj = new A(1, 2);
func.prototype
になるのnull
でしょうか。少し詳しく説明していただけますか?
A.prototype = null;
。その場合new A()
、オブジェクト上でその内部プロトタイプがObject
オブジェクトをポイントします。jsfiddle.net
Object(ret) === ret
。
typeof
テストによって裏で何が行われているのかが理解しやすくなると思います。
ブラウザコンソールで次のコードを試してください。
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の回答を読むことができます:)
return this;
すると同じ出力が得られます。
だからそれはおそらくオブジェクトのインスタンスを作成するためのものではありません
それはまさにそのために使われます。次のように関数コンストラクタを定義します。
function Person(name) {
this.name = name;
}
var john = new Person('John');
ただし、ECMAScriptの追加の利点は、.prototype
プロパティで拡張できるため、次のようなことができます...
Person.prototype.getName = function() { return this.name; }
このコンストラクターから作成されたすべてのオブジェクトgetName
には、アクセスできるプロトタイプチェーンがあるため、現在はを持つことになります。
class
ます。キーワードはありませんが、ほとんど同じことができます。
JavaScript はオブジェクト指向プログラミング言語であり、インスタンスの作成に使用されます。クラスベースではなくプロトタイプベースですが、オブジェクト指向ではないという意味ではありません。
JavaScriptは、オブジェクト指向プログラミングパラダイムをサポートする動的プログラミング言語であり、オブジェクトの新しいインスタンスを作成するために使用されます。
オブジェクトにクラスは必要ありません-JavaScriptはプロトタイプベースの言語です。
すでにいくつかの非常に優れた答えがありますが、私は、以下のケース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
新しい取得)A
し、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
キーワードを見ると、がthis
指す無名関数の呼び出しオブジェクト(コンテキスト)として機能する新しいオブジェクトが作成されFoo
ます。この場合A
、B
(ウィンドウオブジェクトの代わりに)新しく作成されたオブジェクトのプロパティになります。明示的なreturnステートメントがないため、JavaScriptインタープリターはreturnステートメントを強制的に挿入して、new
キーワードの使用によって作成された新しいオブジェクトを返します。
ケース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
キーワードを見ると、がthis
指す無名関数の呼び出しオブジェクト(コンテキスト)として機能する新しいオブジェクトが作成されFoo
ます。ここでも、A
そしてB
新しく作成されたオブジェクトのプロパティになります。しかし、今回は明示的なreturnステートメントがあるため、JavaScriptインタープリターはそれ自体では何もしません。
ケースIIIで注意すべきことは、new
キーワードが原因で作成されているオブジェクトがレーダーから失われたことです。bar
実際には、JavaScriptインタープリターがnew
キーワードのために作成したオブジェクトではない、完全に異なるオブジェクトを指しています。
JavaScripitのDavid Flanaganの引用:The Definitive Guide(6th Edition)、Ch。4、62ページ目:
オブジェクト作成式が評価されると、JavaScriptは最初に、オブジェクト初期化子{}によって作成されたオブジェクトと同じように、新しい空のオブジェクトを作成します。次に、指定された引数を使用して指定された関数を呼び出し、新しいオブジェクトをthisキーワードの値として渡します。関数はこれを使用して、新しく作成されたオブジェクトのプロパティを初期化できます。コンストラクターとして使用するために作成された関数は値を返さず、オブジェクト作成式の値は新しく作成および初期化されたオブジェクトです。コンストラクタがオブジェクト値を返す場合、その値はオブジェクト作成式の値になり、新しく作成されたオブジェクトは破棄されます。
--- 追加情報 ---
上記のケースのコードスニペットで使用される関数は、JSの世界では次のような特別な名前を持っています。
ケースIおよびII-コンストラクター関数
ケースIII-工場機能。ファクトリー関数はnew
、現在のスレッドで概念を説明するために行ったキーワードでは使用しないでください。
これらの違いについては、このスレッドで読むことができます。
時にはコードは言葉よりも簡単です:
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のスタイルを使用しています。これにより、関数の内部と外部での柔軟性が向上します。
B1 = new func2(2);
<-なぜこれがないのB1.y
ですか?
new
キーワードは、関数が実行されている下にコンテキストを変更し、そのコンテキストへのポインタを返します。
new
キーワードを使用しない場合、関数Vehicle()
が実行されるコンテキストは、Vehicle
関数の呼び出し元のコンテキストと同じです。this
キーワードは、同じコンテキストを参照します。を使用するnew Vehicle()
と、新しいコンテキストが作成されるためthis
、関数内のキーワードは新しいコンテキストを参照します。その代わりに、新しく作成されたコンテキストが返されます。
new
キーワードは、コンストラクタ関数からオブジェクトを作成するためにJavaScriptで使用されています。new
キーワードは、コンストラクタ関数呼び出しの前に配置する必要があり、次のことを行います。
this
キーワードを新しく作成されたオブジェクトにバインドし、コンストラクター関数を実行しますfunction Dog (age) {
this.age = age;
}
const doggie = new Dog(12);
console.log(doggie);
console.log(doggie.__proto__ === Dog.prototype) // true
正確に何が起こるか:
const doggie
言う:変数を宣言するためのメモリが必要です。=
よると、この変数を式の後の式で初期化します。=
new Dog(12)
です。JSエンジンは新しいキーワードを確認し、新しいオブジェクトを作成して、プロトタイプをDog.prototypeに設定します。this
値を新しいオブジェクトに設定して実行されます。このステップでは、新しく作成された犬のオブジェクトに年齢が割り当てられます。new
キーワードは、コンストラクタなどの機能を使用してオブジェクトのインスタンスを作成します。例えば:
var Foo = function() {};
Foo.prototype.bar = 'bar';
var foo = new Foo();
foo instanceof Foo; // true
インスタンスprototype
は、コンストラクター関数のを継承します。上記の例を考えると...
foo.bar; // 'bar'
まあ、siごとのJavaScriptは常に元の仕様であるEcmaScriptの実装であるため、プラットフォームごとに大きく異なる可能性があります。
いずれにせよ、実装とは関係なく、ECmaScript仕様に準拠するすべてのJavaScript実装は、オブジェクト指向言語を提供します。ES標準によると:
ECMAScriptは、ホスト環境内で計算を実行し、計算オブジェクトを操作するためのオブジェクト指向プログラミング言語です。
JavaScriptはEcmaScriptの実装であり、したがってオブジェクト指向言語であることに同意しました。new
オブジェクト指向言語での操作の定義では、そのようなキーワードは、特定のタイプのクラス(C#などの場合は匿名タイプを含む)からオブジェクトインスタンスを作成するために使用されると述べています。
EcmaScriptでは、仕様から読み取れるように、クラスを使用しません。
ECMAScriptは、C ++、Smalltalk、Javaなどのクラスを使用しません。代わりに、リテラル表記法やオブジェクトを作成し、プロパティに初期値を割り当てることでオブジェクトのすべてまたは一部を初期化するコードを実行するコンストラクターなど、さまざまな方法でオブジェクトを作成できます。各コンストラクターは、プロトタイプベースの継承と共有プロパティの実装に使用される「プロトタイプ」という名前のプロパティを持つ関数です。オブジェクトは
、新しい式でコンストラクタを使用して作成されます。たとえば、new Date(2009,11)は新しいDateオブジェクトを作成します。newを使用せずにコンストラクターを呼び出すと、コンストラクターに依存する結果が生じます。たとえば、Date()は、オブジェクトではなく現在の日付と時刻の文字列表現を生成します。