web-dev-qa-db-ja.com

JavaScriptの「新しい」キーワードとは何ですか?

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

  • それは何ですか?
  • それはどんな問題を解決しますか?
  • それが適切な場合とそうでない場合
1632
Alon Gubkin

それは5つのことをします:

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

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

new ConstructorFunction(arg1, arg2)

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

これについて最も難しい部分は、ポイント番号2です。すべてのオブジェクト(関数を含む)は、[[[prototype]]}という内部プロパティを持ちます。 onlyは、オブジェクトの作成時に、newObject.create、またはリテラルに基づいて設定することができます(関数のデフォルトはFunction.prototypeです。 Number.prototypeなどに番号を付けます。それはObject.getPrototypeOf(someObject)でのみ読むことができます。この値を設定または読み込む他の方法はnoです。

隠された[[[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

私は このページ を見つける前に、この問題についての大量のゴミを読みました。

2028
Daniel Howard

この機能があるとします。

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

このようにこれをスタンドアロン関数として呼び出すと、次のようになります。

Foo();

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

さて、newを使ってこのように呼びます。

var bar = new Foo();

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

370
JulianR

Daniel Howardの答えに加えて、これは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);
155
basilikum

初心者の方が理解を深めるために

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

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の答え :)を読むことができます

97
Anulal S

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

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

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

var john = new Person('John');

しかしECMAScriptが持っている追加の利点はあなたが.prototypeプロパティで拡張できるということです。

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

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

33
meder omuraliev

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

26
Michael

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

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

13
Greg

いくつかの非常に良い答えが既にありますが、私はcase _ iii _ についての私の観察を強調するためにあなたがnewingしている関数に明示的なreturn文があるとき何が起こるかについて強調します。以下のケースを見てください。

ケース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

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

ケース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.

ここでも、newキーワードを見たJavaScriptインタプリタは、thisによって指される無名関数の呼び出しオブジェクト(コンテキスト上のFoo)として機能する新しいオブジェクトを作成します。繰り返しますが、AおよびBは、新しく作成されたオブジェクトのプロパティになります。しかし、今回は明示的なreturn文を持っているので、JavaScriptインタプリタはnot独自のことをします。

_ iii _ の場合に注意すべきことは、newキーワードによって作成されているオブジェクトがレーダーから失われたことです。 barは実際には完全に異なるオブジェクトを指していますが、これはnewキーワードのためにJavaScriptインタープリターが作成したものではありません。

4
RBT

時々コードは単語より簡単です:

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のスタイルを使用します。

4
rsbkk

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

obj = new Element();
2
erenon

newキーワードは、関数が実行されているコンテキストを変更し、そのコンテキストへのポインタを返します。

newキーワードを使用しない場合、関数Vehicle()が実行されるコンテキストは、Vehicle関数を呼び出すコンテキストと同じです。 thisキーワードは同じコンテキストを参照します。 new Vehicle()を使用すると、新しいコンテキストが作成されるので、関数内のキーワードthisは新しいコンテキストを参照します。あなたが見返りに得るのは、新しく作成されたコンテキストです。

1
Juzer Ali

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

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

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

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

EcmaScriptでは、仕様から読み取ることができるので、クラスは使用しません。

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

1
João Pinho

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

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

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

インスタンスはコンストラクタ関数のprototypeから継承します。それで、上の例を与えられて...

foo.bar; // 'bar'
0
eyelidlessness

概要:

newキーワードは、コンストラクタ関数からオブジェクトを作成するためにJavaScriptで使用されます。 newキーワードはコンストラクタ関数呼び出しの前に配置する必要があり、以下のことを行います。

  1. 新しいオブジェクトを作成します
  2. このオブジェクトのプロトタイプをコンストラクタ関数のprototypeプロパティに設定します。
  3. thisキーワードを新しく作成されたオブジェクトにバインドし、コンストラクタ関数を実行します
  4. 新しく作成されたオブジェクトを返します

例:

function Dog (age) {
  this.age = age;
}

const doggie = new Dog(12);

console.log(doggie);
console.log(doggie.__proto__ === Dog.prototype) // true

正確にはどうなりますか:

  1. const doggieは言います:変数を宣言するためにメモリが必要です。
  2. 代入演算子=は、この変数を=の後の式で初期化します。
  3. 式はnew Dog(12)です。 JSエンジンはnewキーワードを見て、新しいオブジェクトを作成し、プロトタイプをDog.prototypeに設定します。
  4. コンストラクタ関数は、this値を新しいオブジェクトに設定して実行されます。このステップでは、年齢が新しく作成されたドッグオブジェクトに割り当てられます。
  5. 新しく作成されたオブジェクトが返され、変数doggieに割り当てられます。
0