0

I am using https://stackoverflow.com/a/1833851 to clone a function so that I can override it. For example:

Function.prototype.clone = function() {
    var that = this;
    var temp = function temporary() { return that.apply(this, arguments); };
    for(var key in this) {
        if (this.hasOwnProperty(key)) {
            temp[key] = this[key];
        }
    }
    return temp;
};

window.capture_list = [];
window.handler_clone = window.YAHOO.handleData.clone();

window.YAHOO.handleData = function(oRequest, oResponse, oData){
    window.capture_list.push( {'oRequest': oRequest, 'oResponse': oResponse, 'oData': oData} );
    return window.handler_clone( oRequest, oResponse, oData );
};

This appears to achieve the task, but I get a "Maximum call stack size exceeded error" in practice.

It seems like the clone method I'm using is recursing into itself somehow... I think I'm misunderstanding something about this clone implementation due to my limited js experience.

Any thoughts on where this recursion is, or how to better implement the clone for overriding? I'm really just trying to intercept the arguments passed to handler(). Thanks!

the handleData function:

window.YAHOO.handleData = function(oRequest, oResponse, oData) {
    if (oData == null) {
        oData = {}
    }
    oData.totalRecords = oResponse.meta.totalRecords;
    return oData
};
Community
  • 1
  • 1
sam-6174
  • 3,104
  • 1
  • 33
  • 34
  • 1
    Please show us what exactly `/*do something*/` is, and which of those `f`, `g`, `f` functions you are calling how. We currently cannot reproduce your error. – Bergi May 13 '15 at 17:18
  • Btw, there's absolutely no reason to `.clone()` `f` when you are overwriting it anyway! – Bergi May 13 '15 at 17:19
  • @#1 Thanks for your help. I've updated my post to be more specific, although I can't give you the exact code to reproduce. Basically, I am trying to intercept yui xhr requests. – sam-6174 May 13 '15 at 17:29
  • @#2 how would I call the original f() though, from inside the override f()? – sam-6174 May 13 '15 at 17:37
  • For this problem, you can (and should) in fact omit the `.clone()` completely and just do `window.handler_clone = window.YAHOO.handleData;`. However, if you can't make a demo that exhibits the error you're getting, we hardly can help you. It doesn't look like your decorator is the root of the problem. Does it even work without capturing? – Bergi May 13 '15 at 17:38
  • You might want to try `handler_clone.call(window.YAHOO, oRequest, oResponse, oData)` – Bergi May 13 '15 at 17:39
  • Yes, it works just fine before the cloning interceptor. But then I get one of those runaway script error dialogs. I figured maybe that the cloned_to_f() was calling itself after the override since I renamed the cloned_from_f() – sam-6174 May 13 '15 at 17:42
  • No sane implementation should behave like that (but your decorator is a bit off). Is the source of `YAHOO.handleData` online somewhere? Regardless, what is `Object.keys(window.YAHOO.handleData)` (before you've overwritten it)? – Bergi May 13 '15 at 17:48
  • There are no keys, i.e. "[ ]". I've updated the post w/ the function source... hard to see where this gets recursed. – sam-6174 May 13 '15 at 17:55
  • Oh indeed. And where does that function get called? What's the stack trace of your stack overflow? – Bergi May 13 '15 at 17:57
  • I am doing this through selenium. After I apply my interceptor code, I "call" the function by clicking a button to trigger the request. I then do driver.execute_script( "return window.capture_list;" ) -- this is when I get "WebDriverException: Message: u'unknown error: Maximum call stack size exceeded\n (Session info: chrome=34.0.1847.137)\n (Driver info: chromedriver=2.9.248304,platform=Linux 3.2.0-4-amd64 x86_64)'" – sam-6174 May 13 '15 at 18:09
  • Wow, that's not much information to work with. – Bergi May 13 '15 at 18:10
  • Yep. I get the same result when doing like you said with omitting the .clone() -- I need to read up on js decoration – sam-6174 May 13 '15 at 18:14

1 Answers1

0

Stepping through this:

Clone copies this then applies any arguments to the original function, then iterates the keys in function (I am assuming to get the prototype properties?), then returning that back out.

It seems like you are trying to create a decorator?

In any case, I am not sure why you haven't opted to use bind it creates a new function with the context that is passed in.

More here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

lucky7id
  • 385
  • 1
  • 9
  • I knew there had to be a smarter way about this. I'll accept your answer once I confirm. Thanks! – sam-6174 May 13 '15 at 17:33
  • Side note, I have run your prototype, it seems okay, it's probably your callback stack causing the maximum range exception. – lucky7id May 13 '15 at 17:35
  • Sorry for being such a nub... but any hints as to how I could debug the callback for this seeming recursion? The callback is not actually my code – sam-6174 May 13 '15 at 17:43
  • You can throw an exception, and log the stack, the best I can think of right now. – lucky7id May 13 '15 at 17:50