我有一个ActiveX对象(Master),并想在其上动态调用函数。为此,我使用apply()函数。但遗憾的是,InternetExplorer告诉我一些类似的内容:“此对象不支持此方法”。有人能给我一个暗示我能做什么吗?

(为了测试这个,你也可以使用一个小的flash对象作为Master并调用“doSomething”而不是我特定的“Initialize”。)

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

对于比较,这是执行中的apply()函数:

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您的时间和广泛的解释! 可悲的是,我无法以这种方式工作(虽然它适用于警报器) 但它让我想到了使用代理类。这不是最优雅的方式,因为我必须提供我想要使用的对象的所有功能,但它有效并且它不涉及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(而不仅仅是IE)中某些主机对象(即任何非本机对象)的问题在于它们不是从 Function.prototype 继承的(并且通常都不是从顶级 Object.prototype )。某些可能看起来像函数的主机对象实际上与函数无关,只是它们可以被调用。这些对象不从 Function.prototype 继承的事实意味着它们无法通过 instanceof 运算符标识为函数;他们的构造函数没有引用 Function ;并且他们缺少所有 Function.prototype。* 方法,例如 call apply 。甚至它们的内部[[Class]]属性也可能不是“Function”的属性,因为它与任何本机对象一样(注意[[Class]]可以从 Object.prototype.toString <的结果推断出来。 / code> value)。

这实际上是预期的,因为不需要主机对象来实现本机对象所做的许多事情(根据ECMA-262,第3版)。完全允许宿主对象在方法调用上抛出错误(例如 hostObject.hostMethod());或者将其作为操作数传递给标准运算符,如 delete (例如 delete hostObject.hostMethod )。如您所见,可调用主机对象也可以不从本机 Function.prototype 继承。

这种不可预测(但完全符合要求)的行为实际上是建议主机对象增强的主要原因之一。

但回到 call 问题:)

关于这些“棘手”的事情IE主机对象是它们经常实现内部[[Call]]方法,并且可以在它们上调用 call apply ,尽管不是直接

这是一个在没有它的对象上模拟 apply 调用的模式:

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

null 可以替换为应该调用的任何上下文对象。

apply 调用的示例在没有调用的主机对象上:

// 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函数来解决它,以展开正确数量的参数(类似于以前的解决方案,但没有ActiveX对象句柄必须在全局范围内的限制变量)。

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

显然,IE的JS引擎看不到ActiveX函数作为JavaScript函数对象,您可以在其上调用 apply()。如何做一个 eval() - 虽然很难看,但它似乎是你唯一的选择。

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

我想提一下,如果你使用 eval 方法,因为Ates Goral说你需要注意数组中的字符串参数,因为它们将被视为变量名,例如

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