2014-04-21 6 views
1

콜백이 호출되기 직전에 호출되는 "전처리"함수를 생성하려고합니다. 즉, 콜백 호출은 사전 처리 함수 -> 콜백 패턴을 따라야합니다. 이러한 전처리 함수를 "삽입"하려면 단순히 클로저를 만들고 클로저 내부에 콜백을 다시 작성하여 전처리 함수가 호출되도록 한 다음 다시 작성된 콜백이 끝날 때 원래 콜백을 호출 할 수 있습니다.함수 생성자 내에서 사용될 함수 바인딩하기

그러나 전 하나의 전처리 기능을 가지고 있지만 콜백이 여러 개 있습니다. 콜백의 각 호출 앞에는 동일한 전 처리 함수 호출이 선행되어야합니다. 각각의 가능한 콜백에 대해 전처리 콜백을 작성할 필요가 없도록 클로저에서 루프를 만들었습니다.이 변수는 old 변수를 다음 콜백에 할당 한 다음 Function 생성자를 사용하여 콜백을 다시 작성합니다.

모든 기능이 작동합니다. 그러나 원래 액세스 할 수있는 콜백 함수에서 더 이상 전역 변수를 사용할 수 없습니다. variable이 정의되어 있지 않다고 주장하면 (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function에 따라) 다음과 같은 오류가 발생합니다.

(function() { 
    var end = function(init) { 
     /* 
      In here, init is processed. 
      Init contains multiple callbacks. 
      One callback is chosen to be invoked. 
     */ 
     init.callback(); 
    }; 

    var closure = function(init) { 
     var old = init.callback; 
     init.callback = new Function(
      "\ 
       /*\ 
        Do the preprocessual stuff\ 
       */\ 
       console.log(\"The preprocessual functionality has now taken place.\");\ 
       return " + old + ".apply(this, Array.prototype.slice.call(arguments));\ 
      " 
     ); 

     return end.apply(this, Array.prototype.slice.call(arguments)); 
    }; 

    var variable = "value"; 

    closure({ 
     /*among other properties*/ 
     callback: function() { 
      console.log("The preprocessual callback must have been invoked when 'end' invokes me."); 
      console.log(variable); 
     } 
    }); 
})(); 

그래서 그때의 내가 콜백 함수 내 콜백에 필요한 변수 bind 시도하자 생각했다. 나는 매우 이상한 문제에 직면했다. 어떤 이유로 콜백 함수 (Function 생성자가 할 일이 거의없는)에 범위/매개 변수를 바인딩하면 이상한 오류가 발생합니다. 이러한 오류의 작은 예 :

var callback = function() { 
    console.log(arguments); 
}; 

callback = new Function(
    "\ 
    return " + callback + ".apply(this, Array.prototype.slice.call(arguments));\ 
    " 
); 

callback(1, 2, 3); 

작동이 작동하지 않습니다 내가 다른 변수에 콜백을 할당하는 경우 그것은 중요하지 않습니다

var callback = function() { 
    console.log(arguments); 
}.bind(this); 

callback = new Function(
    "\ 
    return " + callback + ".apply(this, Array.prototype.slice.call(arguments));\ 
    " 
); 

callback(1, 2, 3); 

등 사이에 old, 그리고 사용 old 함수 생성자 및 함수 내에서 완전히 다른 바운드 함수를 사용하는 경우 그것은 중요하지 않습니다 const 루머도. 어떤 바운드 함수 (변수를 참조했는지 여부에 관계없이)는 "SyntaxError : missing"요소 목록 뒤에 오류가 발생합니다.

는 사실, 심지어이

callback = new Function(
    "\ 
    return " + (function() {}.bind(this)) + ".apply(this, Array.prototype.slice.call(arguments));\ 
    " 
); 

callback(1, 2, 3); 

실패 그리고이 경우 이유를 알아 내기 위해 실패합니다. 유용한 도움을 주시면 감사하겠습니다. 내가 예상했던대로

var 
    ajax = function(init) { 
     for (var i = 0, callbacks = ["success", "error"]; i < callbacks.length; i++) { 
      if (init.hasOwnProperty(callbacks[i] + "Callback")) { 
       init[callbacks[i] + "Callback"] = new Function("responseText", 
        "\ 
        /*\ 
         Preprocessual callback takes place here (among other things, messages from the server are inserted in the document)\ 
        */\ 
        \ 
        return " + init[callbacks[i] + "Callback"] + ".apply(this, Array.prototype.slice.call(arguments));\ 
        " 
       ); 
      } 
     } 

     // This is the actual ajax function, which can operate independently of the project (in contrary, the preprocessual callback needs to know about where to insert messages in the document) 
     return cregora.ajax.apply(this, Array.prototype.slice.call(arguments)); 
    } 
; 

(function() { 
    // some scope with variables.. 

    ajax({ 
     url: "url", 
     callbackThis: this, 
     successCallback: function(responseText) { 
      console.log("I need some variables available in this scope"); 
     }, 
     errorCallback: function() { 
      console.log("I need some variables available in this scope"); 
     } 
    }); 
})(); 
+0

'normal'함수에서 Function 생성자 + 함수 본문을 문자열로 사용하게하는 단계를 설명해 주시겠습니까? – TheShellfishMeme

+0

@TheShellfishMeme 네, init 객체에 여러 개의 콜백이 있습니다. 모두 앞에 동일한 전 처리 콜백이 있어야합니다. 단 하나의 차이점은 다시 작성된 콜백의 끝에서 호출 될 원래 콜백의 이름 일 것이기 때문에 나는 각자에 대해 99 % 동일한 코드를 작성하려고하지 않습니다. 이 예제에서는 루프를 생략했습니다. – user2180613

+0

그게 내가 너를 이해하는 데 어려움을 겪고있는 곳이다. 그들은 모두 다른 콜백에 동일한 래퍼가 필요합니다. 이런 일은'new Function'을 사용하지 않아도 가능합니다. 그래서 나는 그 질문에 대해 더 궁금하다. 문제를 해결하면 문제를 해결하는 것 같습니다. 그래서 어쩌면 당신은 또한 그 변화를 필요로하는 특정 코드에 링크 할 수 있고 그것을 바꿀 수있는 방법을 지적 할 수 있습니다. – TheShellfishMeme

답변

1

, 실제로 문제를 조금과 복잡함을했다 :

같이, 실제 사용 사례를 요청했다.
함수 생성자를 사용하는 대신 적절한 처리기를 반환하고 함수 (전 처리기와 같은)를 자동으로 래핑하는 상위 순서 함수를 작성할 수 있습니다.원래 콜백 함수를 바인딩

var callbackWrapper = (function createCallbackWrapper() { 
    var preProcessor = function (responseText) { 
     console.log(responseText); 
    }; 

    return function callbackWrapper (callback) { 
     // Returns new anonymous function that acts as the handler 
     return function responseHandler (responseText) { 
      var args = Array.prototype.slice.call(arguments); 
      preProcessor.apply(this, args); 
      callback.apply(this, args); 
     }; 
    }; 
})(); 

지금은 전혀 문제가 없습니다 : 당신이 걱정하는 경우

var callbackWrapper = function (callback) { 
    // Returns new anonymous function that acts as the handler 
    return function responseHandler (responseText) { 
     // Do your pre-processing 
     console.log(responseText); 
     callback.apply(this, Array.prototype.slice.call(arguments)); 
    }; 
}; 

var ajax = function(init) { 
    for (var i = 0, callbacks = ["success", "error"]; i < callbacks.length; i++) { 
     var callbackName = callbacks[i] + "Callback"; 
     if (init.hasOwnProperty(callbackName)) { 
      var callback = init[callbackName]; 
      init[callbackName] = callbackWrapper(callback); 
     } 
    } 

    // This is the actual ajax function, which can operate in independent of the project (for example, the preprocessual callback needs to know about where to insert messages in the document) 
    return cregora.ajax.apply(this, Array.prototype.slice.call(arguments)); 
}; 


(function() { 
    // some scope with variables.. 

    ajax({ 
     url: "url", 
     callbackThis: this, 
     successCallback: function(responseText) { 
      console.log("I need some variables available in this scope"); 
     }, 
     errorCallback: function() { 
      console.log("I need some variables available in this scope"); 
     } 
    }); 
})(); 

은, 당신도 정확히 같은 전처리 기능마다 시간을 사용하도록 callbackWrapper을 변경할 수 있습니다.

문제에 대해 조금 더 설명 :

당신이 fn + ".apply(...)"를 사용

, JS는 문자열로 원래의 기능을 켜집니다. 따라서 클로저 변수 나 var closure 함수 범위 또는 전역 범위에없는 변수에 액세스하는 데 어려움을 겪게됩니다.

함수에서 .bind을 호출 한 후 문자열 표현이 "function() { [native code] }"이되기 때문에 사용자의 경우에도 실패합니다. 물론 이것은 유효한 함수 본문이 아니며 많은 문제를 일으킬 수 있습니다.

문자열로 변환하는 것이 실제 문제이며, 쉽게 해결할 수없는 문제입니다. 따라서 new Function을 사용하면 거의 적절한 해결책이 될 수 없으므로 일단 자신을 찾으면 자신의 추론에 실수했다고 가정해야합니다. 그렇지 않다면 new Function가 실제로 유일한 해결책 일 것입니다.

+0

솔루션의 기초가 보이지 않아서 정말 어리 석습니다. 문자열 변환에 대한 설명을 해 주셔서 감사합니다. – user2180613