Frage

ich habe ein ActiveX-Objekt (Master) und möchte Funktionen aufzurufen dynamisch darauf. Um dies zu tun verwende ich die Anwendung () Funktion. Aber leider das Internetexplorer sagt mir etwas entlang der Linien von: „Dieses Objekt dieser Methode nicht unterstützt“. Kann mir jemand einen Tipp geben, was ich tun könnte?

(Um dies zu testen Sie könnten auch ein kleines Flash-Objekt als Master verwenden und rufen „doSomething“ statt meinem spezifischen „initialisieren“.)

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);
}

Für comparsion, ist dies die Anwendung () Funktion in Aktion:

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);
}
War es hilfreich?

Lösung 4

Danke kangax für Ihre Zeit und Ihre ausführliche Erklärung! Leider konnte ich es auf diese Weise nicht bekommen funktioniert (es funktioniert für die Alertbox though) Aber es hat mich auf die Idee, eine Proxy-Klasse zu verwenden. Es ist nicht die eleganteste Art und Weise, weil ich jede Funktion von meinem Objekt zu schaffen, habe ich verwenden will, aber es funktioniert und es nicht verwickeln 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);
}

Nochmals vielen Dank für Ihre Zeit!

Andere Tipps

Das Problem mit einigen der Host-Objekte (das heißt alle nicht-native Objekte) in IE (und nicht nur IE) ist, dass sie erben nicht von Function.prototype (und oft weder von Top-Level-Object.prototype). Einige Host-Objekte, die könnte wie Funktionen aussehen eigentlich nichts außer mit Funktionen zu tun, dass sie aufgerufen werden können. Die Tatsache, dass diese Objekte erben nicht von Function.prototype bedeutet, dass sie als Funktionen mit instanceof Operator identifiziert werden scheitern; dass ihr Konstruktor nicht Referenzierung Function; und dass es fehlt ihnen an all die Function.prototype.* Methoden, wie call oder apply. Auch ihre interne [[Klasse]] Eigenschaft nicht, dass die „Funktion“ sein könnte, da es mit einem beliebigen nativen Objekt (beachten Sie, dass [[Klasse]] kann aus dem Ergebnis des Object.prototype.toString Wertes abgeleitet werden).

Dies ist eigentlich zu erwarten, da Host-Objekte sind nicht erforderlich , viele Dinge zu implementieren, dass native Objekte tun (gemäß ECMA-262, 3. Aufl.). Es ist ideal für ein Host-Objekt zu, sagen wir, throw Fehler auf Method Invocation (z.B. hostObject.hostMethod()) erlaubt; oder wenn es als ein Operand Standard Operatoren wie delete Passing (z.B. delete hostObject.hostMethod). Wie Sie sehen können, ist es auch OK für aufrufbar Host-Objekte aus nativen Function.prototype erben.

Eine solche unberechenbar (noch vollkommen konform) Verhalten ist tatsächlich einer der Hauptgründe, warum Host-Augmentation-Objekte wird empfohlen, gegen .

Aber zurück zu Ihrem call Problem:)

Die Sache über diese „tricky“ IE Host-Objekte ist, dass sie oft internen [[Aufruf]] implementieren Verfahren, und es ist möglich call und apply auf sie zu berufen, obwohl nicht direkt .

Hier ist ein Muster apply Aufruf auf einem Objekt zu emulieren, die es nicht hat:

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

null kann ersetzt werden, was auch immer Kontextobjekt soll in, natürlich genannt werden.

Und ein Beispiel für apply Aufruf auf dem Host-Objekt, das kein call hat:

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

, um Ihren Code Anwenden

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

Ich hatte das gleiche Problem, und ich löste es durch eine Thunk-Funktion zur Laufzeit kompiliert die richtige Anzahl von Argumenten (ähnlich der bisherigen Lösung entrollen, aber ohne Einschränkung, dass das ActiveX-Objekt-Handle in einem globalen sein muss Variable).

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);
};

Offenbar JS-Engine IE sieht nicht ActiveX-Funktionen wie JavaScript-Funktion Objekte, auf denen Sie apply() aufrufen können. Wie wäre es nur ein eval() tun -. Obwohl hässlich, so scheint es die einzige Möglichkeit zu sein

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

dachte, ich würde erwähnen, dass, wenn Sie die eval Methode verwenden, wie Ates Goral sagte man vorsichtig von String-Argumente im Array sein müssen, da sie Variablennamen in Betracht gezogen werden, zB

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

die eval die Linie übergeben werden

Master.Initialize(1,VC1)

, die einen Fehler aus, wenn VC1 nicht eine definierte Variable ist. Es wäre am besten zu „abrollen“ die Array-Namen anstelle des Führen Literale:

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
}

so aufrufen wird

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

die eval wird dann weitergegeben werden

Master.Initialize(args[0],args[1]);
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top