で別の質問、あるユーザーがキーワードの使用は危険だと指摘しnew
、 を使用しないオブジェクト作成の解決策を提案しましたnew
。私はそれが真実だと信じませんでした。なぜなら、私は主にプロトタイプ、スクリプトおよびその他の優れた JavaScript ライブラリがあり、それらはすべてnew
キーワードを使用していました。
それにもかかわらず、昨日私はYUIシアターでダグラス・クロックフォードの講演を見ていましたが、彼もまったく同じことを言っていました。つまり、彼はコード内でキーワードをもう使わないということですnew
(Crockford による JavaScript 解説 - 第 3 幕: 究極の関数 - 50:23 分)。
キーワードを使うのは「悪い」ことでしょうかnew
?それを使うことのメリットとデメリットは何でしょうか?
ベストアンサー1
Crockford 氏は、優れた JavaScript 技術の普及に多大な貢献をしてきました。言語の重要な要素に対する彼の独断的な姿勢は、多くの有益な議論を巻き起こしました。とはいえ、1 人の意見以上のものを見ることを拒否し、「悪い」または「有害」という宣言を絶対的なものとして受け止める人が多すぎます。時には少しイライラさせられることもあります。
キーワードによって提供される機能を使用すると、new
各オブジェクトを最初から構築する場合に比べていくつかの利点があります。
- プロトタイプの継承クラスベースの OO 言語に慣れている人からは疑惑と嘲笑の混じった目で見られることが多いですが、JavaScript のネイティブ継承テクニックは、コード再利用のシンプルで驚くほど効果的な手段です。そして、
new
キーワードは、それを使用する標準的な (そして唯一利用可能なクロスプラットフォームの) 手段です。 - パフォーマンス。これは、#1 の副作用です。作成するすべてのオブジェクトに 10 個のメソッドを追加したい場合、各メソッドを各新規オブジェクトに手動で割り当てる作成関数を記述するだけで済みます。または、作成関数にメソッドを割り当てて
prototype
、new
新しいオブジェクトをスタンプアウトすることもできます。この方法は高速であるだけでなく (プロトタイプの各メソッドにコードが不要)、メソッドごとに個別のプロパティを持つ各オブジェクトが膨らむのを防ぎます。低速のマシン (または特に低速の JS インタープリター) では、多数のオブジェクトが作成されるときに、時間とメモリを大幅に節約できます。
そして、new
他の回答でうまく説明されているように、1 つの重大な欠点があります。使用し忘れると、警告なしにコードが壊れます。幸いなことに、この欠点は簡単に軽減できます。関数自体に少しコードを追加するだけです。
function foo()
{
// if user accidentally omits the new keyword, this will
// silently correct the problem...
if ( !(this instanceof foo) )
return new foo();
// constructor logic follows...
}
new
誤って使用することで生じる問題を心配することなく、メリットを享受できるようになります。
ジョン・レシグはこの技術について、シンプルな「クラス」インスタンス化この投稿には、この動作を「クラス」にデフォルトで組み込む手段も含まれています。間違いなく読む価値があります...彼の次の本も同様です。JavaScript 忍者の秘密では、この機能や JavaScript 言語のその他の多くの「有害な」機能の中に隠された金脈を見つけています (の章with
は、当初この悪評高い機能を単なる小技として無視していた私たちにとって特に啓発的です)。
汎用的な健全性チェック
壊れたコードが黙って動作しているという考えが気になる場合は、チェックにアサーションを追加することもできます。または、いくつかのコメントされている場合は、チェックを使用して実行時例外を導入します。
if ( !(this instanceof arguments.callee) )
throw new Error("Constructor called as a function");
このスニペットでは、前の例とは異なり、実際にオブジェクトをインスタンス化する必要がないため、コンストラクター関数名のハードコーディングを回避できることに注意してください。したがって、変更せずに各ターゲット関数にコピーできます。
ES5は奪う
としてショーン・マクミラン、ステフェンベズそしてjrharguments.callee
ES5では の使用は無効です。厳密モードしたがって、上記のパターンをそのコンテキストで使用するとエラーが発生します。
ES6と全く無害なnew
ES6ではクラスJavaScript へ - いいえ、昔ながらの Crockford がやったような奇妙な Java の模倣方法ではなく、精神的には彼 (および他の人) が後に採用した軽量な方法に非常に近く、プロトタイプ継承の最良の部分を取り入れ、一般的なパターンを言語自体に焼き付けました。
...その一部には金庫も含まれていますnew
:
class foo
{
constructor()
{
// constructor logic that will ONLY be hit
// if properly constructed via new
}
}
// bad invocation
foo(); // throws,
// Uncaught TypeError: class constructors must be invoked with 'new'
しかし、新しいシュガーを使用したくない場合はどうすればよいでしょうか。完全に正常な旧式のプロトタイプ コードを、上記のような安全性チェックを使用して更新し、厳密モードで動作し続けたい場合はどうすればよいでしょうか。
だけでなくニック・パーソンズ氏のコメントES6では、次のような便利なチェック機能も提供しています。new.target
:
function foo()
{
if ( !(new.target) )
throw new Error("Constructor called as a function");
// constructor logic follows...
}
したがって、どちらのアプローチを選択する場合でも、少し考えて衛生管理を行えば、new
害なく使用することができます。