2012-03-05 9 views
3

彼の「Good Parts」では、「new」を決して使用しないことを提案しています。このルールに従うには、次のコードをどのようにリファクタリングしますか?'New'を置き換えるルール

function Range(from, to) { 
    this.from = from; 
    this.to = to; 
} 

Range.prototype = { 
    includes: function(x) { 
     return this.from <= x && x <= this.to; 
    }, 

    foreach: function(f) { 
     for(var x = Math.ceil(this.from); x <= this.to; x++) f(x); 
    }, 

    toString: function() { 
     return "(" + this.from + "..." + this.to + ")"; 
    } 
}; 

// Here are example uses of a range object 
var r = new Range(1,3); // Create a range object 
r.includes(2); // => true: 2 is in the range 
r.foreach(console.log); // Prints 1 2 3 

私は彼のadditional adviceを発見、この(おそらく非常に一般的な)場合には、それをどのように適用するか明確ではありませんでした。巨大なオブジェクトリテラルを含むファクトリ関数を作成することを提案しますか?もしそうなら、それは非効率的ではない?そのようなファクトリ関数は、呼び出すたびに重複関数を作成します。つまり、共有カスタムメソッドを保持するプロトタイプはありません。

彼のアドバイスで何か言われていないようですが、私は誰かがそれをクリアできることを望んでいます。

+6

「new」は使用しないでください。それに全く同意できません。 –

+0

このスレッドを読んでみませんか:http://stackoverflow.com/questions/383402/is-javascript-s -new-キーワードと見なされる有害なもの –

+1

Crockfordの「提案」はまさにそれであり、塩の穀物でそれらを取ってください。 –

答えて

2

は、ここで私はあなたがこれを達成する方法を示しています使用しないでnew

Range = function(from, to) { 

    function includes(x) { 
     return this.from <= x && x <= this.to; 
    } 

    function foreach(f) { 
     for (var x = Math.ceil(this.from); x <= this.to; x++) f(x); 
    } 

    function toString(){ 
     return "(" + this.from + "..." + this.to + ")"; 
    } 

    return { 
     from: from, 
     to: to, 
     includes: includes, 
     foreach: foreach, 
     toString: toString 
    }; 
}; 

var r = Range(1, 3); 
console.log(r.includes(2)); // => true: 2 is in the range 
r.foreach(console.log); // Prints 1 2 3 

これは単なる例ですが、私はw hat @nnnnnnは言っています - "適切な場合にのみ使用してください。私に関する限り、あなたの問題のコードはnewの使用完全に罰金ですリファクタリングする必要はありません「

EDIT:。

コード下記のは、機能の重複するインスタンスを作成しないようにします

Range = function(from, to) { 
    return { 
     from: from, 
     to: to, 
     includes: Range.includes, 
     foreach: Range.foreach, 
     toString: Range.toString 
    }; 
}; 

Range.includes = function(x) { 
    return this.from <= x && x <= this.to; 
} 

Range.foreach = function (f) { 
    for (var x = Math.ceil(this.from); x <= this.to; x++) f(x); 
} 

Range.toString = function() { 
    return "(" + this.from + "..." + this.to + ")"; 
} 
+0

しかし、このファクトリ関数は、呼び出されるたびにメソッドの重複定義を作成しませんか? 「新しい」アプローチからそれほど効率的ではないでしょうか? –

+0

私はあなたの質問から理解したことは、あなたが "重複"と言ったときに間違っていたと思います。今私は正しく理解する。はい。それで合っています。私の最初の例は、 'Range'の各呼び出しでこれらの関数を動的に作成します。これを避けるには、オブジェクトを使用する必要があります。しかし、これらの関数は宣言されているスコープ内のすべてにアクセスできます。 – Diode

1

私は彼がこのような何かやって示唆していると思う:

function Range(from, to) { 
    if (!(this instanceof Range)) { 
    return new Range(from, to); // Yes, the new operator is used here, but... 
    } 

    this.from = from; 
    this.to = to; 
} 

// ... now, the rest of the world can create ranges WITHOUT the new operator: 
var my_range = Range(0, 1); 
+0

多分それはちょうど私ですが、 'instanceof'を使って、' new'を使った方がずっと悪いです(新しいものを使っても何か問題がないと言っても) – NicoSantangelo

+0

私はこのパターンの魅力を理解しています。他の人のためのJSライブラリを提供し、私は彼らが私が提供したドキュメントを無視し、誤って 'new'を使わずにコンストラクタ関数を呼び出すかもしれないと心配しましたが、私は自分のコードで使用するとは思わない:クライアントコードが 'new'で呼び出すことを期待しています。私がファクトリとして機能するファンクションを望むならば、それに応じて、例えばRange()ではなく 'getRange()'のように名前を付けると思います。 – nnnnnn

0

私はこのテクニックを愛するが、私は保証インスタンスとして、それを参照してください。

var Range = function fn(from, to) { 
    if (!(this instanceof fn)) { 
     return new fn(from, to); 
    }; 
    this.from = from; 
    this.to = to; 
} 

Range.prototype = { 
    includes: function(x) { 
     return this.from <= x && x <= this.to; 
    }, 

    foreach: function(f) { 
     for(var x = Math.ceil(this.from); x <= this.to; x++) f(x); 
    }, 

    toString: function() { 
     return "(" + this.from + "..." + this.to + ")"; 
    } 
}; 

// Here are example uses of a range object 
var r = new Range(1,3); // Create a range object 
r.includes(2); // => true: 2 is in the range 
r.foreach(console.log); // Prints 1 2 3 
関連する問題