JavaScript : ActiveX-Object 및 apply ()-기능의 문제
-
07-07-2019 - |
문제
ActiveX 객체 (마스터)가 있으며 함수를 동적으로 호출하고 싶습니다. 이를 위해 apply () 함수를 사용합니다. 그러나 슬프게도 InternetexPlorer는 "이 개체는이 방법을 지원하지 않습니다"라는 줄을 따라 무언가를 말해줍니다. 누군가 내가 할 수있는 일을 힌트를 줄 수 있습니까?
(이것을 테스트하기 위해 작은 플래시 객체를 마스터로 사용하고 특정 "초기화"대신 "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의 경우, 이것은 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]] 속성조차도 기본 객체와 마찬가지로 "기능"의 속성이 아닐 수도 있습니다 ([[class]]는 결과에서 추론 될 수 있습니다. Object.prototype.toString
값).
이것은 실제로 예상됩니다 호스트 객체는 필요하지 않습니다 기본 물체가하는 많은 것들을 구현하기 위해 (ECMA-262, 3rd ed.). 호스트 객체가 메소드 호출에 오류를 던지는 것이 완벽하게 허용됩니다 (예 : 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
아니오가없는 호스트 객체에서 호출 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"]);
나는이 같은 문제를 겪었고 런타임에 덩어리 함수를 컴파일하여 올바른 수의 인수를 풀어서 해결했습니다 (이전 솔루션과 유사하지만 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 엔진 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]);