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


1744

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

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

10
また、関連するスレッド- stackoverflow.com/questions/383402/...
チェタンSastry

これらの例を最初に読んでください、developer.mozilla.org
en

回答:


2145

5つのことを行います。

  1. 新しいオブジェクトを作成します。このオブジェクトのタイプは単にobjectです。
  2. この新しいオブジェクトの内部のアクセスできない[[prototype]](つまり__proto__)プロパティを、コンストラクター関数の外部のアクセス可能なプロトタイプオブジェクトに設定します(すべての関数オブジェクトには自動的にプロトタイププロパティがあります)。
  3. それは作るthis新しく作成されたオブジェクトに変数のポイントを。
  4. this言及された場合は常に、新しく作成されたオブジェクトを使用して、コンストラクター関数を実行します。
  5. コンストラクター関数が非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

私は最終的にこのページを見つける前に、この主題について大量のゴミを読みました。このページは、素晴らしい図で非常によく説明されています。


47
追加したかっただけです。実際には、__ proto__によって内部[[プロトタイプ]]にアクセスする方法があります。ただし、これは非標準であり、比較的新しいブラウザーでのみサポートされています(すべてのブラウザーではサポートされていません)。標準化された方法、つまりObject.getPrototypeOf(obj)が登場しますが、これはEcmascript3.1であり、それ自体が新しいブラウザでのみサポートされます。ただし、通常はそのプロパティを使用しないことをお勧めします。
Blub

9
質問:がObjMaker値を返す関数として定義されている場合、何が違うのですか?
ジム・ブラックラー

13
@LonelyPixel newが存在するため、関数/オブジェクトを構築/コピーするためにファクトリメソッドを記述する必要はありません。これは、「これをコピーして、親の「クラス」のようにすること、効率的かつ正確に実行すること、そして私、JSのみが内部でアクセスできる継承情報を保存すること」を意味します。これを行うにprototypeは、新しいオブジェクトのアクセスできない内部オブジェクトを変更して、継承されたメンバーを不透明にカプセル化し、従来のOO継承チェーン(ランタイムで変更できない)を模倣します。なしnewでこれをシミュレートできますが、継承はランタイムで変更可能になります。良い?悪い?あなた次第。
エンジニア

11
追加する小さなポイント:newキーワードが前に付くと、コンストラクターへの呼び出しは、作成されたオブジェクトを自動的に返します。コンストラクタ内から明示的に返す必要はありません。
チャーリーロバーツ2013

7
と言うメモがありますNotice that this pattern is deprecated!。クラスのプロトタイプを設定するための正しい最新のパターンは何ですか?
TomPažourek14年

400

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

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で、プロパティAとを持つオブジェクトになりますB。どの関数もコンストラクターにすることができますが、常に意味があるわけではありません。


7
実行コンテキストによって異なります。私の場合(Qtスクリプト)、それは単なるグローバルオブジェクトです。
Maxym 2013年

2
これによりメモリ使用量が増加しますか?
ユルゲンポール

2
windowは関数を呼び出したオブジェクトなので -でなければなりません:windowは関数を含むオブジェクトだからです。
デヴィッド・Horvathの

1
@Taurus Webブラウザでは、メソッド以外の関数はwindow暗黙的にメソッドになります。閉鎖の場合でも、匿名の場合でも。ただし、この例では、ウィンドウでの単純なメソッド呼び出しです:Foo();=> [default context].Foo();=> window.Foo();。この式にwindowコンテキストがあります(重要なのは発信者だけではありません)。
デヴィッド・Horvathの

1
@おうし座基本的にはい。ただし、ECMA 6および7では物事はより複雑です(ラムダ、クラスなどを参照)。
デイビット・ホーバス

164

ダニエルハワードの回答に加えて、ここで何をするか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);

73
私はjavascriptが英語よりも理解しやすいことを発見しました:v
damphat '20年

すばらしい答えです。小さな質問が1つあります。どうすれば可能func.prototypeになるのnullでしょうか。少し詳しく説明していただけますか?
TomPažourek14年

6
@tompプロトタイププロパティを上書きするには、単に次のように記述しますA.prototype = null;。その場合new A()、オブジェクト上でその内部プロトタイプがObjectオブジェクトをポイントします。jsfiddle.net
basilikum

2
ホストオブジェクトが「オブジェクト」や「関数」とは異なるものを生成する可能性があるため、チェックのタイプが間違っている可能性があります。何かがオブジェクトであるかどうかをテストするには、私が好むObject(ret) === ret
Oriol

2
@オリオールさんコメントありがとうございます。あなたが言うことは本当であり、実際のテストはより堅牢な方法で行う必要があります。ただし、この概念的な答えについては、typeofテストによって裏で何が行われているのかが理解しやすくなると思います。
basilikum

109

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

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

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


4
いい答えです。また、除外return this;すると同じ出力が得られます。
ネルー2017

37

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

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

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

var john = new Person('John');

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

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

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


6
関数コンストラクタはクラスのように使用されclassます。キーワードはありませんが、ほとんど同じことができます。
meder omuraliev 2009年

クラスのキーワードがあります-クラスは将来の使用のために予約されています
グレッグ

11
あなたはCSSクラスを設定するの.class .classNameを使用していない理由ちなみにだこと
グレッグ

23
慣例により、大文字で大文字にする必要があります。
eomeroff 2013年

27

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


6
JavaScriptは、これらすべてのクラスベースの言語よりもオブジェクト指向であるように思われます。JavaScriptでは、記述したものはすべてすぐにオブジェクトになりますが、クラスベースの言語では、最初に宣言を記述し、後で初めてクラスの特定のインスタンス(オブジェクト)を作成します。また、JavaScriptプロトタイプは、クラスベースの言語のVTABLEに関することを漠然と思い出させるようです。
JustAMartin 2013年

14

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

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


12

すでにいくつかの非常に優れた答えがありますが、私は、以下のケース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ます。この場合AB(ウィンドウオブジェクトの代わりに)新しく作成されたオブジェクトのプロパティになります。明示的な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、現在のスレッドで概念を説明するために行ったキーワードでは使用しないください

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


あなたのケース3はgr8の観察です
appu

5

時にはコードは言葉よりも簡単です:

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のスタイルを使用しています。これにより、関数の内部と外部での柔軟性が向上します。


3
B1 = new func2(2); <-なぜこれがないのB1.y ですか?
sunny_dev 2015年

@sunny_dev私はJSの専門家ではありませんが、おそらくfunc2が内部値(これ)で動作/返すのではなく、値(zオブジェクト)を直接返すためです
Eagle

5

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

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


これは、範囲に関して非常に洞察に満ちた答えです。答えへのGr8の追加。
appu

3

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

obj = new Element();

2

概要:

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

  1. 新しいオブジェクトを作成します
  2. このオブジェクトのプロトタイプをコンストラクター関数のプロトタイププロパティに設定します
  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エンジンは新しいキーワードを確認し、新しいオブジェクトを作成して、プロトタイプをDog.prototypeに設定します。
  4. コンストラクター関数は、this値を新しいオブジェクトに設定して実行されます。このステップでは、新しく作成された犬のオブジェクトに年齢が割り当てられます。
  5. 新しく作成されたオブジェクトが返され、変数doggieに割り当てられます。

1

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

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

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

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

foo.bar; // 'bar'

2
新しいキーワードは基本的に、関数をコンストラクターとしてすでに関連付けています。何も返す必要はありません。あなたはただ行うことができます:function foo(x){this.bar = x; } var obj = new foo(10); alert(obj.bar);
reko_t 2009年

特に目的がない限り、目的のためにコンストラクタ関数からオブジェクトを返す必要はありません。たとえば、(何らかの理由で)毎回新しいオブジェクトを作成するのではなく、特定のオブジェクトインスタンスを返す必要がある場合などです。しかし、あなたの例では、それは完全に不要です。
Chetan Sastry、

まあ、それは例でした。オブジェクト返すことができます。このシナリオでは多くのパターンが使用されていますが、「たとえば」として提供したので、私の言葉は「たとえば」です。
まぶたがない2009年

1

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

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

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

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

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.