سؤال

لدي ActiveX كائن (ماجستير) و ترغب في استدعاء وظائف حيوي على ذلك.للقيام بذلك يجب استخدام تطبيق() وظيفة.ولكن للأسف Explorer يقول لي شيئا على غرار:"هذا لا يعتمد الكائن هذه الطريقة".شخص ما يمكن أن تعطيني تلميحا ما يمكنني فعله ؟

(هذا الاختبار يمكنك أيضا استخدام فلاش صغير وجوه سيد الاتصال "doSomething" بدلا من بلدي محددة "تهيئة".)

function invoke(object, fnName, args)
{
  return object[fnName].apply(object, args);
}

function test_it()
{
  try{
    Master = window.document["Master"];
  }
  catch(e){alert(e);}
  var param = [1,"VC2"]; 
  var ret = invoke(Master, "Initialize", param);
  alert("got: "+ret);
}

بالنسبة comparsion هذا هو تطبيق() وظيفة في العمل:

function Obj()
{
  this.msg = function(a, b, c)
  {
      alert("msg: \n a: "+a+"\n b: "+b+"\n c: "+c);
      return "hi";
  }
    return this;
}


function invoke(object, fnName, args)
{
  return object[fnName].apply(object, args);
}

function test_it()
{
  var obj = new Obj();
  var ret = invoke(obj, "msg", [1, 2, 3]);
  alert("got: "+ret);
}
هل كانت مفيدة؟

المحلول 4

شكرا kangax على وقتك الشرح المستفيض!للأسف لم أتمكن من الحصول عليه العمل بهذه الطريقة(يعمل من أجل alertbox على الرغم من) لكنه قادني إلى فكرة استخدام وكيل الدرجة.انها ليست الطريقة الأكثر أناقة لأنه يجب أن نقدم كل وظيفة من وجوه أريد استخدام لكنه يعمل وأنها لا تنطوي على eval()!

function proxy(obj)
{
    this.obj = obj;

    this.Initialize = function(a, b)
    {
        return obj.Initialize(a, b);
    }   
}

function test_it()
{
    var myMaster = new proxy(window.document["Master"]);    
    var ret = myMaster["Initialize"].apply(myMaster, [1, "VC2"]);
    alert(ret);
}

مرة أخرى شكرا على وقتك!

نصائح أخرى

المشكلة مع بعض الكائنات المضيفة (أيأي غير أصلية الكائنات) في أي (وليس فقط IE) هو أنها لا ترث من Function.prototype (و في كثير من الأحيان لا من أعلى مستوى Object.prototype).استضافة بعض الكائنات التي قد تبدو مثل وظائف في الواقع لا علاقة لها وظائف إلا أنها يمكن أن يسمى.حقيقة أن هذه الكائنات لا ترث من Function.prototype يعني أنها تفشل في التعرف على الوظائف مع instanceof المشغل ؛ أن منشئ هو عدم الرجوع Function;وأنهم يفتقرون إلى كل من Function.prototype.* أساليب مثل call أو apply.حتى الداخلية [[الصف]] الخاصية قد لا يكون من "وظيفة", كما هو الحال مع أي كائن أصلي (لاحظ أن [[الصف]] يمكن استنتاجها من نتيجة Object.prototype.toString القيمة).

هذا هو في الواقع الأمطار, منذ المضيف الكائنات غير مطلوبة لتنفيذ العديد من الأشياء التي مواليد الأشياء (كما في ECMA-262, 3rd ed.).هو تماما يسمح لمجموعة كائن إلى رمي الخطأ على استدعاء الأسلوب (مثل hostObject.hostMethod());أو عندما يمر على أنها المعامل على مستوى شركات مثل delete (مثلا ، delete hostObject.hostMethod).كما يمكنك أن ترى, بل هو أيضا طيب بالنسبة للاستدعاء المضيف الكائنات لا يرث من الأم Function.prototype.

هذه لا يمكن التنبؤ بها (حتى الآن متوافقة تماما) السلوك هو في الواقع واحدة من الأسباب الرئيسية لماذا المضيف الكائنات تكبير يوصى ضد.

ولكن مرة أخرى إلى call المشكلة :)

الشيء حول هذه "صعبة" أي المضيف الكائنات التي غالبا ما تنفذ الداخلية [[دعوة]] الطريقة ، فمن الممكن أن تحتج call و apply عليها ، على الرغم من لا مباشرة.

وهنا نمط محاكاة apply الاحتجاج على كائن أن لا يكون ذلك:

function f(){ return arguments };
Function.prototype.apply.call(f, null, [1,2,3]); // [1,2,3] 

null يمكن استبدال مع أي كائن سياق في ، بالطبع.

و مثال على apply الاحتجاج على استضافة كائن لا call:

// should work in IE6, even though `alert` has no `call` there
Function.prototype.call.call(alert, window, 'test');

تطبيقه على الرمز الخاص بك

// Calls Master.initialize borrowing from Function.prototype
Function.prototype.apply.call(Master.initialize, Master, [1,"VC2"]);

وكان لي نفس هذه المشكلة وأنا حلها عن طريق وضع الدالة thunk في وقت التشغيل في انبسط العدد الصحيح من الحجج (على غرار الحل السابق، ولكن من دون تقييد أن مؤشر كائن اكتف يجب أن يكون في عالمي متغير).

varArgsThunkFunctionsCache = [];

function getVarArgsThunkFunction(arrayLength) {
  var fn = varArgsThunkFunctionsCache[arrayLength];
  if (!fn) {
    var functionCode = 'return o[m](';
    for (var i = 0; i < arrayLength; ++i) {
      if (i != 0) {
        functionCode += ','
      }
      functionCode += 'a[' + i + ']';
    }
    functionCode += ')';
    fn = new Function('o', 'm', 'a', functionCode);
    varArgsThunkFunctionsCache[arrayLength] = fn;
  }
  return fn;
};


function invoke(object, methodName, args) {
  var fn = getVarArgsThunkFunction(args.length);
  return fn(object, methodName, args);
};

ويبدو أن محرك JS IE للا يرى ظائف اكتف ككائنات وظيفة جافا سكريبت التي يمكنك الاتصال apply(). ماذا عن مجرد القيام على eval() - على الرغم من القبيح، يبدو أن لديك الخيار الوحيد

function invoke(objectName, fnName, args) {
    return eval(objectName + "." + fnName + "(" + args + ")");
}

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

function invoke(objectName, fnName, args) {
    return eval(objectName + "." + fnName + "(" + args + ")");
}
invoke("Master", "Initialize", [1, "VC1"]);

وسيتم تمرير eval خط

Master.Initialize(1,VC1)

والتي سوف يرمي خطأ إذا VC1 ليس متغير محددة. قد يكون من الأفضل أن "انبسط" اسم مجموعة بدلا من الحرفية مرور:

function UnrollArray(arrayname, length) {
    var s = "";
    for(var i = 0; i < length; i++) {
        s += arrayname + "[" + i + "],";
    }
    return s.substring(0, s.length - 1); //remove the trailing comma
}

والاحتجاج حتى يصبح

function invoke(objectName, fnName, args) {
    var unrolledarray = UnrollArray("args", args.length);
    return eval(objectName + "." + fnName + "(" + unrolledarray + ");");
}
invoke("Master", "Initialize", [1, "VC1"]);

وبعد ذلك يتم تمرير eval

Master.Initialize(args[0],args[1]);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top