JavaScript:ActiveX 对象和 apply() 函数的问题
我有一个 ActiveX 对象(主)并且想动态调用它的函数。为此,我使用 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);
}
i have an ActiveX Object (Master) and would like to invoke functions dynamically on it. To do this i use the apply() Function. But sadly the InternetExplorer tells me something along the lines of: "This Object doesn't support this Method". Can someone give me a hint what i could do?
(To test this you also could use a small flash object as Master and call "doSomething" instead of my specific "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);
}
For comparsion, this is the apply() Function in action:
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);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
发布评论
评论(5)
我遇到了同样的问题,我通过在运行时编译一个 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);
};
感谢 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);
}
再次感谢您的宝贵时间!
只是想我会提到,如果您使用 eval
方法,如 Ates Goral 所说,您需要小心数组中的字符串参数,因为它们将被视为变量名称,例如
function invoke(objectName, fnName, args) {
return eval(objectName + "." + fnName + "(" + args + ")");
}
invoke("Master", "Initialize", [1, "VC1"]);
eval< /code> 将传递到将引发错误的行
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]);
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
IE(不仅是 IE)中的一些宿主对象(即任何非本机对象)的问题是它们不是从
Function.prototype
继承的(通常也不是从顶级Function.prototype
继承的)代码>Object.prototype)。一些可能看起来像函数的宿主对象实际上与函数无关,只是它们可以被调用。事实上,这些对象不是从Function.prototype
继承的,这意味着它们无法被instanceof
运算符识别为函数;他们的构造函数没有引用Function
;并且它们缺少所有Function.prototype.*
方法,例如call
或apply
。甚至它们的内部 [[Class]] 属性也可能不是“Function”的属性,就像任何本机对象一样(请注意,[[Class]] 可以从Object.prototype.toString 值)。
这实际上是预期的,因为不需要主机对象来实现本机对象所做的许多事情(根据 ECMA-262,第 3 版)。主机对象完全可以在方法调用时抛出错误(例如
hostObject.hostMethod()
);或者将其作为操作数传递给标准运算符(例如delete
)(例如delete hostObject.hostMethod
)。正如您所看到的,可调用宿主对象不继承自本机Function.prototype
也是可以的。这种不可预测(但完全合规)的行为实际上是建议反对主机对象增强的主要原因之一。
但回到你的
call
问题:)这些“棘手”的 IE 主机对象的问题是它们经常实现内部 [[Call]] 方法,并且可以调用
call
code> 并对其进行应用
,尽管不是直接。下面是一个在没有它的对象上模拟
apply
调用的模式:当然,
null
可以替换为应该调用的任何上下文对象。还有一个在没有
call
的主机对象上调用apply
的示例:将其应用到您的代码
The problem with some of the host objects (i.e. any non-native objects) in IE (and not only IE) is that they don't inherit from
Function.prototype
(and often neither from top levelObject.prototype
). Some host objects that might look like functions actually have nothing to do with functions except that they can be called. The fact that these objects don't inherit fromFunction.prototype
means that they fail to be identified as functions withinstanceof
operator; that their constructor is not referencingFunction
; and that they lack all of theFunction.prototype.*
methods, such ascall
orapply
. Even their internal [[Class]] property might not be that of "Function", as it is with any native object (note that [[Class]] can be inferred from the result ofObject.prototype.toString
value).This is actually expected, since host objects are not required to implement many things that native objects do (as per ECMA-262, 3rd ed.). It is perfectly allowed for a host object to, say, throw error on method invocation (e.g.
hostObject.hostMethod()
); or when passing it as an operand to standard operators likedelete
(e.g.delete hostObject.hostMethod
). As you can see, it is also OK for callable host objects to NOT inherit from nativeFunction.prototype
.Such unpredictable (yet perfectly compliant) behavior is actually one of the main reasons why host objects augmentation is recommended against.
But back to your
call
problem : )The thing about these "tricky" IE host objects is that they often implement internal [[Call]] method, and it is possible to invoke
call
andapply
on them, although not directly.Here's a pattern to emulate
apply
invocation on an object that doesn't have it:null
can be replaced with whatever context object should be called in, of course.And an example of
apply
invocation on host object that has nocall
:Applying it to your code