كيف يمكنني إنشاء كائن باستخدام مجموعة من قيم المعلمات بدلا من إدراجها في جافا سكريبت ؟

StackOverflow https://stackoverflow.com/questions/813383

سؤال

هل هذا ممكن ؟ أنا خلق قاعدة واحدة مصنع وظيفة القيادة المصانع من أنواع مختلفة (ولكن لديها بعض أوجه التشابه) و أريد أن تكون قادرة على تمرير الحجج مجموعة إلى قاعدة مصنع ثم ربما يقوم بإنشاء مثيل جديد من الكائن ملء حجج منشئ الطبقة ذات الصلة عبر صفيف.

في جافا سكريبت أنه من الممكن استخدام صفيف إلى استدعاء دالة مع حجج متعددة باستخدام تطبيق الأسلوب:

namespace.myFunc = function(arg1, arg2) { //do something; }
var result = namespace.myFunc("arg1","arg2");
//this is the same as above:
var r = [ "arg1","arg2" ];
var result = myFunc.apply(namespace, r);

لا يبدو كما لو أن هناك أي إنشاء مثيل كائن باستخدام تطبيق على الرغم من هناك ؟

شيء مثل (لم ينجح):

var instance = new MyClass.apply(namespace, r);
هل كانت مفيدة؟

المحلول

وجرب هذا:

var instance = {};
MyClass.apply( instance, r);

وجميع الكلمة "الجديد" لا يتم تمرير في كائن جديد إلى منشئ التي تصبح بعد ذلك هذا المتغير داخل الدالة منشئ.

وهذا يتوقف على كيفية كتابة منشئ، قد تضطر إلى القيام بذلك:

var instance = {};
var returned = MyClass.apply( instance, args);
if( returned != null) {
    instance = returned;
}

تحديث: يقول تعليق هذا لا يعمل إذا كان هناك نموذج أولي. جرب هذا.

function newApply(class, args) {
    function F() {
        return class.apply(this, args);
    }
    F.prototype = class.prototype;
    return new F();
}

newApply( MyClass, args);

نصائح أخرى

علما بأن

  • new myClass()
    

    دون أي حجج قد تفشل لأن منشئ وظيفة قد تعتمد على وجود الحجج.

  • myClass.apply(something, args)
    

    سوف تفشل في كثير من الحالات خاصة إذا دعت الأم دروس التاريخ أو عدد.

أنا أعرف أن "eval هو الشر", ولكن في هذه الحالة قد تحتاج إلى محاولة التالية:

function newApply(Cls, args) {
    var argsWrapper = [];
    for (var i = 0; i < args.length; i++) {
        argsWrapper.push('args[' + i + ']');
    }
    eval('var inst = new Cls(' + argsWrapper.join(',') + ');' );
    return inst;
}

بسيطة على هذا النحو.

(يعمل نفس Instance.New في هذا بلوق وظيفة)

والمأجورون والمأجورون والخارقة، ولكن ربما هذا هو واحد من أكثر قليلا أنيقة من بعض الآخرين، لأن الدعوة تركيب سيكون على غرار ما تريد، وأنك لن تحتاج إلى تعديل الطبقات الأصلية في كل شيء:

Function.prototype.build = function(parameterArray) {
    var functionNameResults = (/function (.{1,})\(/).exec(this.toString());
    var constructorName = (functionNameResults && functionNameResults.length > 1) ? functionNameResults[1] : "";
    var builtObject = null;
    if(constructorName != "") {
       var parameterNameValues = {}, parameterNames = [];
       for(var i = 0; i < parameterArray.length; i++) {
         var parameterName = ("p_" + i);
         parameterNameValues[parameterName] = parameterArray[i];
         parameterNames.push(("parameterNameValues." + parameterName));
       }
       builtObject = (new Function("parameterNameValues", "return new " + constructorName + "(" + parameterNames.join(",") + ");"))(parameterNameValues);
    }
    return builtObject;
};

والآن يمكنك أن تفعل أي من هذه لبناء كائن:

var instance1 = MyClass.build(["arg1","arg2"]);
var instance2 = new MyClass("arg1","arg2");

ومنح، والبعض قد لا ترغب تعديل نموذج الكائن وظيفة، لذلك يمكنك أن تفعل ذلك بهذه الطريقة واستخدامها بوصفها وظيفة بدلا من ذلك:

function build(constructorFunction, parameterArray) {
    var functionNameResults = (/function (.{1,})\(/).exec(constructorFunction.toString());
    var constructorName = (functionNameResults && functionNameResults.length > 1) ? functionNameResults[1] : "";
    var builtObject = null;
    if(constructorName != "") {
       var parameterNameValues = {}, parameterNames = [];
       for(var i = 0; i < parameterArray.length; i++) {
         var parameterName = ("p_" + i);
         parameterNameValues[parameterName] = parameterArray[i];
         parameterNames.push(("parameterNameValues." + parameterName));
       }
       builtObject = (new Function("parameterNameValues", "return new " + constructorName + "(" + parameterNames.join(",") + ");"))(parameterNameValues);
    }
    return builtObject;
};

وبعد ذلك كنت اسميها مثل ذلك:

var instance1 = build(MyClass, ["arg1","arg2"]);

وهكذا، وآمل أن تكون مفيدة لشخص ما - أنها تسمح لك لترك مهام البناء الأصلي وحده، والحصول على ما كنت بعد في خط واحد بسيط من التعليمات البرمجية (على عكس هذين الخطين تحتاج لالمحدد حاليا، حل / الحل .

وردود الفعل هو موضع ترحيب وتقدير.


وUPDATE: واحد الشيء الآخر أن نلاحظ - محاولة خلق حالات من نفس النوع مع هذه الأساليب المختلفة ومن ثم التحقق لمعرفة ما إذا خصائص المنشئ لها هي نفسها - قد ترغب أن يكون الأمر كذلك إذا كنت في حاجة من أي وقت مضى للتحقق من نوع كائن. ما أعنيه هو أفضل يتضح من التعليمات البرمجية التالية:

function Person(firstName, lastName) {
   this.FirstName = firstName;
   this.LastName = lastName;
}

var p1 = new Person("John", "Doe");
var p2 = Person.build(["Sara", "Lee"]);

var areSameType = (p1.constructor == p2.constructor);

وحاول أن مع بعض الخارقة أخرى ونرى ما سيحدث. من الناحية المثالية، وتريد لها أن تكون من نفس النوع.


والتحذير: كما لوحظ في التعليقات، وهذا لن ينجح لتلك الوظائف منشئ التي تم إنشاؤها باستخدام بناء الجملة وظيفة مجهول، أي

MyNamespace.SomeClass = function() { /*...*/ };

ما لم إنشاء لهم مثل هذا:

MyNamespace.SomeClass = function SomeClass() { /*...*/ };

والحل I الواردة أعلاه قد أو قد لا يكون مفيدا لك، تحتاج إلى فهم بالضبط ما تقومون به من أجل التوصل إلى أفضل الحلول لتلبية الاحتياجات الخاصة بك، وعليك أن تكون مدركا لما يجري لجعل بلدي حل "العمل". إذا كنت لا أفهم كيف يعمل حل بي، وقضاء الوقت لأنها من أصل الرقم.


وALTERNATE الحل: لا أحد التغاضي خيارات أخرى، وهنا هي واحدة من الطرق الأخرى التي يمكن أن الجلد هذا القط (مع المحاذير على غرار النهج المذكور أعلاه)، وهذا واحد أكثر من ذلك بقليل مقصور على فئة معينة:

function partial(func/*, 0..n args */) {
   var args = Array.prototype.slice.call(arguments, 1);
   return function() {
      var allArguments = args.concat(Array.prototype.slice.call(arguments));
      return func.apply(this, allArguments);
   };
}

Function.prototype.build = function(args) {
   var constructor = this;
   for(var i = 0; i < args.length; i++) {
      constructor = partial(constructor, args[i]);
   }
   constructor.prototype = this.prototype;
   var builtObject = new constructor();
   builtObject.constructor = this;
   return builtObject;
};

واستمتع!

وماذا عن الحل؟

function MyClass(arg1, arg2) {

    this.init = function(arg1, arg2){
        //if(arg1 and arg2 not null) do stuff with args
    }

    init(arg1, arg2);
}

ولكن كيف يمكنك:

var obj = new MyClass();
obj.apply(obj, args);

واحتمال واحد هو لجعل عمل المنشئ بمثابة دعوة وظيفة عادية.

function MyClass(arg1, arg2) {
    if (!(this instanceof MyClass)) {
        return new MyClass(arg1, arg2);
    }

    // normal constructor here
}

وسوف الشرط على بيان if يكون صحيحا في حالة استدعاء MyClass بوصفها وظيفة طبيعية (بما في ذلك مع call / apply طالما أن حجة this ليست MyClass object).

والآن كل هذه يعادل:

new MyClass(arg1, arg2);
MyClass(arg1, arg2);
MyClass.call(null, arg1, arg2);
MyClass.apply(null, [arg1, arg2]);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top