web-dev-qa-db-ja.com

JavaScript:良い部分-「新しい」をまったく使用しない方法

Crockfordの本JavaScript:The Good Partsは、コンストラクター関数はalwaysに最初の大文字(つまり、ポイント)を付けた名前を付ける必要があると述べています(114ページ)。初期大文字の関数名はonlyをコンストラクター関数で使用する必要があります(他のすべてはlowerCaseでなければなりません)。

この規則は、コンストラクタ関数でnew演算子を使用することを忘れないようにするのに役立ちます。

彼は続けて"[a] nさらに良い対処戦略は、newをまったく使用しないことです。"

私の質問は、newをまったく使用せずにJavaScriptをどのようにプログラミングすればよいですか?

  • リテラル_{}_および_[]_を使用すると、new Object()およびnew Array()を回避できます。
  • _0_、true、および_''_を使用して、new Number()new Boolean()、およびnew String()を回避できます。
  • _/pattern/_のようなものでnew RegExp()を避けることができます。

new Date()をどのように回避しますか?

そして、最も重要なのは、独自のカスタムオブジェクトでnewを使用しないようにする方法ですか?

57
Rudiger

Crockfordは、 http://developer.yahoo.com/yui/theater/ で利用可能な彼のJavascriptトークの1つでJS自身によって提供されるべきオブジェクト作成関数の例を提供します。

ただし、YUI(3)チーム自体は「new」を使用しており、彼らは彼の推奨に従います(彼はYahooのチーフJSアーキテクトであるため(更新:彼は移動しましたが、この応答が最初に書かれたときは声明は真実でした)。この特定の声明は、「アカデミック」レベルであり、言語が「正しい」ように設計されているべきであり、クラスベースの継承のものの一部ではないはずです。 JSは競合していますが、プロトタイプに基づいていますが、これは「クラシッククラス」継承言語の1つです。

ただし、JSはそのままなので、「new」を使用します。

彼のオブジェクト作成関数はここにあります: http://javascript.crockford.com/prototypal.html

_ if (typeof Object.create !== 'function') {
     Object.create = function (o) {
         function F() {}
         F.prototype = o;
         return new F();
     };
 }
 newObject = Object.create(oldObject);
_


編集:Crockfordのその機能の最新バージョンを使用するように更新されました-3つあります。


[〜#〜] update [〜#〜]2015年6月: Object.create(...) forかなり長い間、現在のすべてのブラウザがサポートしている(IE 9以上)なので、Crockfordの関数を使用する必要はありませんでした。

ただし、、_Object.create_を使用する場合は、それをあまり行わないことを確認する必要があります。その関数は、new Constructor()

説明(V8エンジンの場合)については http://mrale.ph/blog/2014/07/30/constructor-vs-objectcreate.html を、そして http:/ /jsperf.com/object-create-vs-crockford-vs-jorge-vs-constructor/62 パフォーマンスデモ用。

new Constructor(...)に背を向けないもう1つの理由は、ほとんどのJavascript開発者がクラスベースの言語から来ているという単純な理由だけであっても、 ES6クラス が確実に広範囲の採用を見ることです。

for_Object.create_: http://davidwalsh.name/javascript-objects-deconstruction を主張するこの記事もチェックしてください。

好むと好まざるとにかかわらず、特に広い範囲の人々と共有したいプロジェクトでは(空間と時間-正しい、または時間の経過を意味し、他の人々があなたから引き継いでいる)new

[〜#〜] update [〜#〜]2015年9月:私自身、すべてのES 2015 Javascriptを使用し始めました-いずれかのioを使用します。 jsおよび/またはBabel。 new Error(...)などのJavascriptビルトインを除き、プロジェクトでanynewも使用しません。私ははるかに強力な機能的アプローチを使用することを好み、オブジェクトシステムを完全に無視します。 _[my-object].prototype_とthisは私のプロジェクトから完全に削除されました。長い間、私は「オブジェクトがうまく機能するため」これらのアイデアに非常に懐疑的でした。しかし、新しい(io.js)プロジェクトの開始時に非常に渋々試してみた後、「クリック」され、20年を無駄にした理由がわかりません。そうではありませんが、今日ではJSエンジンとハードウェアがそのスタイルをはるかに助長しています。特にES 2015では、thisおよびclass(_constructorFn.prototype_の使用に基づく新しいES 2015キーワードまたはコンセプト全体)を完全に含まない機能スタイルを提供することをお勧めします。数週間かかる場合がありますが、「クリック」すると、二度と戻らないことを約束します-自発的ではありません。とても便利で強力です。

[〜#〜] update [〜#〜]2018年2月:前回のアップデートで書いたことをまだやっている間に、時々それを追加したいクラスは大丈夫です。絶対的なものはありません。 :-)

41
Mörre

new Date()またはnew XMLHttpRequest()を回避する方法がわかりません。しかし、私は自分のタイプにnewを使用するのを避ける方法を知っています。

まず、Object.create()から始めます。これはES5メソッドであるため、どこでも利用できるわけではありません。 es5-shim 、adを使用して追加したら、準備は完了です。

私はモジュールパターンが好きなので、最初に自己実行型の匿名関数var Xyz = (function() {...})()で型をラップします。これは、グローバルな名前空間を混乱させることなく動作するプライベートスペースがあることを意味します。 create()関数とprototypeプロパティを持つオブジェクトを返します。 create()関数は、私のタイプのユーザー向けです。必要な場合は、Xyz.create()を呼び出し、新しい、初期化されたタイプのオブジェクトを取得します。 prototypeプロパティは、人々が継承したい場合に利用可能です。

次に例を示します。

var Vehicle = (function(){
        var exports = {};
        exports.prototype = {};
        exports.prototype.init = function() {
                this.mph = 5;
        };
        exports.prototype.go = function() {
                console.log("Going " + this.mph.toString() + " mph.");
        };

        exports.create = function() {
                var ret = Object.create(exports.prototype);
                ret.init();
                return ret;
        };

        return exports;
})();

継承は次のようになります。

var Car = (function () {
        var exports = {};
        exports.prototype = Object.create(Vehicle.prototype);
        exports.prototype.init = function() {
                Vehicle.prototype.init.apply(this, arguments);
                this.wheels = 4;
        };

        exports.create = function() {
                var ret = Object.create(exports.prototype);
                ret.init();
                return ret;
        };

        return exports; 

})();
12
Sean McMillan

newを使用せず、盲目的にCrockfordをフォローするのはばかげています。

JavaScriptを理解し、適切なコードを記述します。 newキーワードの使用は、JavaScript OOのCornerstoneです。

newを回避することにより、多くの優れたJavaScriptコードを見逃すことになります。

ツールキットから巨大なチャンクを勝手に切り取るのではなく、学習して、代わりに適切に使用してください。

Crockfordには、JavaScriptでコードのバグを引き起こしたものはすべて悪いと言う習慣があります。

私は個人的に"[a] nさらに優れた対処戦略は有能であることです。"

11
Raynos

あなたはcanファクトリ関数を作成することでnewを避けます:

var today = Date.getToday();

(あなたが疑問に思っている場合、あなたはできないファクトリー関数自体でそれを避けます:)

Date.getToday = function() { return new Date(); };

セマンティック値を追加する場合(上記の場合)またはコンストラクターパラメーターの一部を既定にできる場合にのみ、このような関数を作成する必要があると思いますが。言い換えれば、newを使用してavoidだけにしないでください。

6
Jordão

この質問はすでに質問され回答されています: JavaScriptの「新しい」キーワードは有害と見なされますか?

Raynosが言ったように、whyを理解せずにCrockford(または他の誰か)を盲目的に追うことは、彼らがすることを言うのは愚かです。

5
Stephen

newat allを使用しないという彼のアドバイスは、概念的な(アカデミックな)ものであり、文字どおりに解釈されるべきではないと思います。 Dateクラスは、ルールの完全な例外です。標準ECMAScriptを使用して、現在の(または任意の)日付オブジェクトを他にどのように取得できるのでしょうか?

ただし、独自のカスタムオブジェクトでnewを使用しないことに関しては、いくつかの戦略を使用できます。 1つは、コンストラクターの代わりにファクトリーのようなメソッドを使用することです。コンストラクターは、引数としてオブジェクトインスタンスを取得して新しい型に「祝福」するか、デフォルトで新しいオブジェクトリテラルを使用します。以下を考慮してください。

var newCar = function(o) {
  o = o || {};
  // Add methods and properties to "o"...
  return o;
}
3
maerics
function F() { return { /* your fields and methods here */ } }
1
Murali VP

「新規」を使用して他の人のオブジェクトをインスタンス化することにこだわっています。しかし、独自のコードでは、「this」と「new」の両方の落とし穴を回避できます。

(ところで、問題は実際には「新しい」自体にはありません。しかし、「新しい」でインスタンス化されているオブジェクトは、おそらく内部的に「this」を使用しています。「this」を使用すると、 'callerを呼び出して、呼び出されたメソッドを適切なオブジェクトにバインドするための追加の作業を行う必要があります。誤ったバインディングは、実行前にリントまたはその他の方法で検出するのが困難です。

ショートバージョン:

「new」を使用して作成したオブジェクトをインスタンス化しないようにするには、関数からオブジェクトを返すだけです。その関数内で、そのオブジェクトにメソッドを添付し、初期化を行います。これで完了です。この関数はクラス定義とコンストラクターの両方です。

ロングバージョン、例:

次の「self」パターンは、「new」と「this」の両方の使用を避けます。パターンは各オブジェクトにメソッドのコピーを保存しますが、実行時に多くのオブジェクトを作成しない限り、これは問題になりません。その場合、 http://justjs.com/posts/this-considered-harmful の「flyweight」パターンをいつでも使用できます。 (このページの例ではまだ「this」を少し使用していますが、次のパターンに合わせて調整するのは少し微調整です。)

// this function defines a "class" -- the whole function is the constructor
function Foo(x) {
    // create/init whatever object type you want here
    var self = {x: x};
    // if subclassing, for instance, you can do:
    // var self = Baz(x);

    // public method
    self.foo = function() {
        return self.x;
    };

    // public method
    self.bar = function() {
        console.log(self.x);
        logger();
    };

    // private method
    function logger() {
        console.log(self.x);
    }

    // ...more constructor bits can go here

    // don't forget to return self
    return self;
}

var f = Foo(1); 
var g = Foo(2); 
setTimeout(f.bar, 1000);
setTimeout(g.bar, 1000);

console.log(g.foo()); // 2
g.x = 5;
console.log(f.foo()); // 1
console.log(g.foo()); // 5

// ...then, 1 second later:
// 1  (from f.bar)
// 1  (from f.logger)
// 5  (from g.bar)
// 5  (from g.logger)

// blows up if uncommented
// f.logger();
1
stevegt

匿名オブジェクトを返し、コンストラクターでクロージャーを使用することにより、「新規」を回避できます。これは、個人データを隠すのにも役立ちます。

考慮してください:

function SomeCounter(start) {

    var counter = start;

    return {
        getCounter : function() {
            return counter;
        },

        increaseCounter : function() {
            counter++;
        }

    };
}

これを使用するために必要なことは、

var myCounter = SomeCounter(5);
myCounter.increaseCounter();
console.log(myCounter.getCounter()); //should log 6

これの利点は、「新しい」を使用することを覚えておく必要がないことですが、それを実行してもあなたを傷つけることはありません。

var myCounter = new SomeCounter(5); //still works
1