24

I'm trying to hook into a function that loads Facebook's news feed:

UIIntentionalStream.instance && UIIntentionalStream.instance.loadOlderPosts();

on Facebook.com.

Is there a way for me to do this with my own JavaScript? Basically, I need to have some sort of callback - when that function is called, I'd like my own function to be called.

4 Answers 4

37

A more complete method will be:

var old = UIIntentionalStream.instance.loadOlderPosts;
UIIntentionalStream.instance.loadOlderPosts = function(arguments) {
    // hook before call
    var ret = old.apply(this, arguments);
    // hook after call
    return ret;
};

This makes sure that if loadOlderPosts is expecting any parameters or using this, it will get the correct version of them as well as if the caller expects any return value it will get it

Sign up to request clarification or add additional context in comments.

2 Comments

The arguments parameter to your function isn't actually doing anything here. arguments is a keyword in Javascript. It's available inside the function regardless of the parameters, so your function should simply be function().
Instead of "arguments" use "...args". This additionally works inside eval and also forces the arguments to be passed over as array so you don't miss a single one
16

Try something like this:

var old = UIIntentionalStream.instance.loadOlderPosts;
UIIntentionalStream.instance.loadOlderPosts = function() {
    // hook before call
    old();
    // hook after call
};

Just hook in wherever you want, before or after the original function's call.

1 Comment

maybe suggest wrapping the function instead of monkeypatching it
8

Expanding on the previous posts: I have created a function that you can call to perform this "hooking" action.

hookFunction(UIIntentionalStream.instance, 'loadOlderPosts', function(){
    /* This anonymous function gets called after UIIntentionalStream.instance.loadOlderPosts() has finished */
    doMyCustomStuff();
});



// Define this function so you can reuse it later and keep your overrides "cleaner"
function hookFunction(object, functionName, callback) {
    (function(originalFunction) {
        object[functionName] = function () {
            var returnValue = originalFunction.apply(this, arguments);

            callback.apply(this, [returnValue, originalFunction, arguments]);

            return returnValue;
        };
    }(object[functionName]));
}

Bonus: You should also wrap this all a closure, for good measure.

Comments

5

Similar to Eric's answer above. When using ES6, this function works for both async and sync functions:

export function createHook(obj, targetFunction, hookFunction) {
    let temp = obj[targetFunction]
    obj[targetFunction] = function (...args) {
        let ret = temp.apply(this, args)
        if (ret && typeof ret.then === 'function') {
            return ret.then((value)=>{hookFunction([value, args]); return value;})
        } else {
            hookFunction([ret, args])
            return ret
        }
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.