22

次のコードで問題が明確になると思います。

// My class
var Class = function() { console.log("Constructor"); };
Class.prototype = { method: function() { console.log("Method");} }

// Creating an instance with new
var object1 = new Class();
object1.method();
console.log("New returned", object1);

// How to write a factory which can't use the new keyword?
function factory(clazz) {
    // Assume this function can't see "Class", but only sees its parameter "clazz".
    return clazz.call(); // Calls the constructor, but no new object is created
    return clazz.new();  // Doesn't work because there is new() method
};

var object2 = factory(Class);
object2.method();
console.log("Factory returned", object2);
4

7 に答える 7

27

「工場」のない、よりシンプルでクリーンな方法

function Person(name) {
  if (!(this instanceof Person)) return new Person(name);
  this.name = name;
}

var p1 = new Person('Fred');
var p2 = Person('Barney');

p1 instanceof Person  //=> true
p2 instanceof Person  //=> true
于 2012-05-31T15:23:46.163 に答える
7

本当にキーワードを使用したくなくnew、Firefox のみをサポートすることに問題がない場合は、自分でプロトタイプを設定できます。Dave Hintonの回答をそのまま使用できるため、これには何の意味もありません。

// This is essentially what the new keyword does
function factory(clazz) {
    var obj = {};
    obj.__proto__ = clazz.prototype;
    var result = clazz.call(obj);
    return (typeof result !== 'undefined') ? result : obj;
};
于 2009-10-16T23:57:27.183 に答える
3

JavaScript にはクラスがないため、質問を言い換えさせてください: new キーワードを使用せずに、既存のオブジェクトに基づいて新しいオブジェクトを作成する方法は?

「new」を使わない方法です。これは厳密には「の新しいインスタンス」ではありませんが、「新しい」を使用しない (そして ECMAScript 5 の機能を使用しない) 唯一の方法だと思います。

//a very basic version that doesn't use 'new'
function factory(clazz) {
    var o = {};
    for (var prop in clazz) {
        o[prop] = clazz[prop];
    }
    return o;
};

//test
var clazz = { prop1: "hello clazz" };
var testObj1 = factory(clazz);
console.log(testObj1.prop1);    //"hello clazz" 

気を取り直してプロトタイプを設定することもできますが、そうするとクロスブラウザーの問題が発生するので、私はこれをシンプルに保とうとしています。また、「hasOwnProperty」を使用して、新しいオブジェクトに追加するプロパティをフィルタリングすることもできます。

「new」を使用する他の方法がありますが、それを非表示にします。以下は、JavaScript の Object.create 関数から借用したものです: The Good Parts by Douglas Crockford :

//Another version the does use 'new' but in a limited sense
function factory(clazz) {
    var F = function() {};
    F.prototype = clazz;
    return new F();
};

//Test
var orig = { prop1: "hello orig" };
var testObj2 = factory(orig);
console.log(testObj2.prop1);  //"hello orig"

EcmaScript 5 には Object.create メソッドがあり、これはこれをはるかにうまく行いますが、新しいブラウザー (IE9、FF4 など) でのみサポートされていますが、ES5 Shimなどのポリフィル(亀裂を埋めるもの) を使用して、古いブラウザ用の実装を入手してください。( Object.create を含む新しい ES5 機能に関する John Resig の記事を参照してください)。

ES5 では、次のように実行できます。

//using Object.create - doesn't use "new"
var baseObj = { prop1: "hello base" };
var testObj3 = Object.create(baseObj);
console.log(testObj3.prop1);

それが役立つことを願っています

于 2011-04-22T15:00:18.647 に答える
3

ブラウザに依存しないソリューションの方が良いと思います

function empty() {}

function factory(clazz /*, some more arguments for constructor */) {
    empty.prototype = clazz.prototype;
    var obj = new empty();
    clazz.apply(obj, Array.prototype.slice.call(arguments, 1));
    return obj;
}
于 2010-04-11T13:06:14.170 に答える
2

別の方法:

var factory = function(clazz /*, arguments*/) {
    var args = [].slice.call(arguments, 1);
    return new function() { 
        clazz.apply(this, args)
    }
}
于 2013-06-04T14:49:22.847 に答える