I need to trigger function bar() whenever function foo() fires. I have no control over function foo or whether it will change in the future. I have this situation regularly (and I hate it).
I wrote this function to add my code to the end of function foo:
function appendToFunction(fn,code){
if(typeof fn == 'function'){
var fnCode = fn.toString() ;
fnCode = fnCode.replace(/\}$/,code+"\n}") ;
window.eval(fnCode); // Global scope
return true ;
}
else{
return false ;
}
}
eg:
appendToFunction(foo,"bar();");
This strikes me as a terrible idea - but it works. Can somebody point me in a better (safer) direction please.
EDIT: foo is not a specific function, but many functions that I wind up dealing with. They don't change dynamically in the page. But they may be changed (eg. form validation demands) from time to time.
Solution:
I settled on a modified version of Adam's Answer. It's not perfect, but it's better than what I had:
var oldFoo = foo ;
foo = function(){
var result = oldFoo.apply(this, arguments);
bar();
return result ;
}
NB. Watch out for some native functions in IE6/7 that don't have an .apply() method.
You can just override foo with a custom function that calls the original.
E.g.
var old_foo = foo;
foo = function() {
old_foo();
bar();
}
You should also pass any arguments foo takes into it via your replacement function.
function extend(fn,code){
return function(){
fn.apply(fn,arguments)
code.apply(fn,argumnets)
}
}
and use it like this:
function appendToFunction(fn,code){
if(typeof fn == 'function'){
var fnCode = fn.toString() ;
fnCode = fnCode.replace(/\}$/,code+"\n}") ;
window.eval(fnCode); // Global scope
return true ;
}
else{
return false ;
}
}
appendToFunction = extend(appendToFunction,function(){/*some code*/});
this will give you the same "this" in both functions
You could do something like this: THE DEMO.
function foo() {
console.log('foo');
}
function appendToFunction(fn, callback) {
window[fn] = (function(fn){
return function() {
fn();
callback();
}
}(window[fn]));
}
appendToFunction('foo', function(){console.log('appended!')});
foo();
Hmm, this concerns me as well, you mentioned that
I have this situation regularly (and I hate it).
Do you mind if I ask in what scenario this keeps occurring? Is it in a corporate scale, or on a personal project scope? You've clearly got a level head on your shoulders and know that what you're doing is out of the ordinary, so I'm wondering if there is an alternatively solution.
The reason I ask is; this approach could potentially open a can of problems. What if foo fails for example, or if foo returns a value mid evaluation? By simply appending bar to the actual function doesn't guarantee it will execute. Pre-pending it on the other hand means it's more likely to be executed, but still in my opinion isn't a good approach.
Have you considered revising the function foo? I know this might seem like a silly question, but it might be worth it if you're encountering similar problems throughout. If you want to keep things abstracted you could adopt an "event handler" approach, whereby foo triggers an event on the window, which in turn then triggers bar, would this work in your case.
Alternatively, if you know what foo is, and what it does, you could hook into it's prototype if it's an object, and then amend the code there appropriately. You did however mention that this function is open to change, which may make this option redundant, but it's a possible solution nonetheless.
You can append or prepend some new code to an existing function just merging them using for example:
function mergeFunctions(function1, function2, instance1, instance2, numberOfArgumentsToPassToFunc1) {
return function() {
var _arguments = Array.prototype.slice.apply(arguments);
var _arguments1 = _arguments.slice(0, numberOfArgumentsToPassToFunc1);
var _arguments2 = _arguments.slice(numberOfArgumentsToPassToFunc1);
var that = this;
(function(function1, function2) {
if (typeof function1 == "function") {
if (typeof instance1 != "undefined") {
function1.apply(instance1, _arguments1);
}
else if (that == window) {
function1.apply(function1, _arguments1);
}
else {
var compare = mergeFunctions(function(){}, function(){});
if (that.toString() == compare.toString()) {
function1.apply(function1, _arguments1);
}
else {
function1.apply(that, _arguments1);
}
}
}
if (typeof function2 == "function") {
if (typeof instance2 != "undefined") {
function2.apply(instance2, _arguments2);
}
else if (that == window) {
function2.apply(function2, _arguments2);
}
else {
var compare = mergeFunctions(function(){}, function(){});
if (that.toString() == compare.toString()) {
function2.apply(function2, _arguments2);
}
else {
function2.apply(that, _arguments2);
}
}
}
})(function1, function2);
}
}
A basic example would be the following:
// Original function:
var someFunction = function(){
console.log("original content");
};
// Prepend new code:
// --------------------------------------------------------
someFunction = mergeFunctions(function() {
console.log("--- prepended code");
}, someFunction);
// Testing:
someFunction();
// Outout:
// [Log] --- prepended code
// [Log] original content
// Append new code:
// --------------------------------------------------------
someFunction = mergeFunctions(someFunction, function() {
console.log("appended code");
});
// Testing:
someFunction();
// Output:
// [Log] --- prepended code
// [Log] original content
// [Log] appended code
Note that the merging function tries to apply the expected 'this' to the merged parts, otherwise you can just simply pass the wanted 'this' to them, as well as you can handle the relative arguments.
A more general example could be the following:
function firstPart(a, b) {
console.log("--- first part");
console.log("'this' here is:");
console.log(this.name);
console.log("a: "+a);
console.log("b: "+b);
}
function MyObject() {
this.x = "x property of MyObject";
}
MyObject.prototype.secondPart = function (y) {
console.log("");
console.log("--- second part");
console.log("'this' here is:");
console.log(this.name);
this.x = y;
console.log("x: "+this.x);
}
MyObject.prototype.merged = mergeFunctions(firstPart, MyObject.prototype.secondPart, firstPart, MyObject, 2);
// Testing
var test = new MyObject();
test.merged("a parameter", "b parameter", "x parameter overrides x property of MyObject");
// Console output:
// [Log] --- first part
// [Log] 'this' here is:
// [Log] firstPart
// [Log] a: a parameter
// [Log] b: b parameter
// [Log]
// [Log] --- second part
// [Log] 'this' here is:
// [Log] MyObject
// [Log] x: x parameter overrides x property of MyObject
Related
I need the current function name as a string to log to our log facility. But arguments.callee.name only works in loose mode. How to get the function name under "use strict"?
For logging/debugging purposes, you can create a new Error object in the logger and inspect its .stack property, e.g.
function logIt(message) {
var stack = new Error().stack,
caller = stack.split('\n')[2].trim();
console.log(caller + ":" + message);
}
function a(b) {
b()
}
a(function xyz() {
logIt('hello');
});
You can bind function as its context then you can access its name via this.nameproperty:
function x(){
console.log(this.name);
}
x.bind(x)();
After little research here is a good solution :
function getFnName(fn) {
var f = typeof fn == 'function';
var s = f && ((fn.name && ['', fn.name]) || fn.toString().match(/function ([^\(]+)/));
return (!f && 'not a function') || (s && s[1] || 'anonymous');
}
function test(){
console.log(getFnName(this));
}
test = test.bind(test);
test(); // 'test'
Source : https://gist.github.com/dfkaye/6384439
Building on #georg solution, this one returns just the function name. Note though that it may fail if called from an anonymous function
function getFncName() {
const stackLine = (new Error())!.stack!.split('\n')[2].trim()
const fncName = stackLine.match(/at Object.([^ ]+)/)?.[1]
return fncName
}
function Foo() {
console.log(getFncName()) // prints 'Foo'
}
A simple solution to dynamically retrieve function names [like magic variables] is the use of scoped variables, and the Function.name property.
{
function foo() {
alert (a.name);
}; let a = foo
}
{
function foo2() {
alert(a.name)
}; let a = foo2
};
foo();//logs foo
foo2();//logs foo2
Note: Nested functions cease to be source elements, and are hence not hoisted. Also, this technique cannot work with anonymous functions.
If (like me) you want to define this elsewhere and call it generically, you can store the code as a string somewhere global or import it, then eval() it wherever to access the current function name. (Using eval keeps the context at the point of invocation.)
There's gotta be a way to do this without using a string, but whatever.
SomeObject.whatFunc =
'const s = new Error().stack;' +
"const stackLine = new Error().stack.split('\\n')[2].trim();" +
'const fncName = stackLine.match(/(?<=at )(.*)(?= \\()/gm)[0];' +
'console.log(fncName);'
// Whereever you want the func name
function countBananas('weeee') {
eval(SomeObject.whatFunc)
// blah blah blah
}
countBananas() // logs 'countBananas'
just an update to get the full name :
function logIt(message) {
var stack = new Error().stack,
// update is on this line
caller = stack.split('\n')[2].trim().split(/\s+/)[1];
console.log(caller.trim().split(/\s+/)[1];);
}
function a(b) {
b()
}
a(function xyz() {
logIt('hello');
});
I'm trying to override a Javascript function that is included in a .js file that I cannot modify(it is served from a server our applications aren't deployed on). The function contains functions and variables within it. There is one sub-function that I need to change the behavior of but it is called by another, I can't call it directly. Here it is:
Simplistic version of included file that I can't change:
com.company.topLevelFunc = function () {
var a = null;
var b = null;
var doSomething = function() {
a = foo;
b = bar;
};
var get = function(cfg) {
//do stuff
};
return {
//other vars and functions here
getValue : function (cfg) {
cfg.url=a + b;
get(cfg);
}
};
}();
The function I need to override is the get(cfg). However, I can't call it directly, I need to go through the getValue(cfg) method and preserve all the other stuff that goes on in the top level function. So I've been trying to override both as follows:
My JS that I full control over, and doesn't work, it errors on the apply saying that 'missing : after property id". Am I doing this correct, not sure how to get the apply to work correctly?
var topLevel = com.company.topLevelFunc;
myTopLevel = function() {
var myGet = function(cfg) {
//do simliar but different stuff from the original get function
};
return {
topLevel.apply(this, arguments);
getMyValue : function (cfg) {
cfg.c= a + b +"some other string";
//do something
myGet(cfg);
}
};
}();
Unfortunately for you, the get method is private. It only exists inside the body of a an anonymous function nobody has access to. Aside from some very clever hacks and unrecommended programming, there is nothing you can do to change it.
What you should do in this case is change the getValue property of com.company.topLevelFunc. The way you are attempting to do that is slightly wrong and i will explain why.
a = function() { // this is not a
var c = function() { return 3; };
return { // this object is a
b : c;
}
}(); // called immediately
In this construct, a is not a function. The function you see there is invoked immediately and a is assigned the return value of that invocation. In fact this is almost equivalent:
a = { b : function() { return 3; } };
Why you would use the first construct instead of the second is a question asked many times here. A short answer is that the first allows you to have private stuff that nobody else can access (like your get method).
So a is an object with a property who's value is a function that returns 3. If you want a to return 4, you need to do something like this:
a.b = function() { return 4; }
This keeps the other properties of a intact (if it had any) and only changes the property you are interested in.
If you want b to access some private properties defined in the anonymous function above, it simply cannot be done.
Basically I want to do this:
someFunction() // do something
someFunction.somePropertyFunction()
someFunction() // Now someFunction is modified; it should now exhibit a different behaviour
Is this possible?
EDIT:
I'm not looking for what #Kolink was suggesting. Basically I want to augment a function's functionality by calling one of it's property function.
Specifically, I need to: 1. have access to the original function inside my property function (which is entirely doable using this), and 2. bind a new function to the original function's name (which I'm not sure if it's possible).
Just to be clear, I don't have access to the internal definition of the function that I want to augment. I want to attach a function to Function.prototype (so that it will be available as a property of the function that I want to augment), and then I will call func.augmentThis(), and then func should be augmented. But I'm not sure how, hence the question :P
Easily. Here's an example:
var derp = 123;
someFunction = function() {alert(derp);};
someFunction.somePropertyFunction = function() {derp = 456;};
someFunction(); // alerts 123
someFunction.somePropertyFunction();
someFunction(); // alerts 456
Okay, that's an oversimplified example, but yeah, it's entirely possible.
If your question is whether a function attached as a property to another function has a way to access the function to which it is attached, the answer is no. After all, the same function could be attached to any number of functions of objects.
So one alternative is to explicitly refer to the "mother" function within the function that is attached to it and intended to change its behavior:
function f (n) { alert (n + f.offset); }
f.offset = 0;
f.change_offset = function (i) { f.offset = i; };
f (1); //1
f.change_offset (100);
f (1); //101
Here, f is hard-wired into the definition of change_offset. If this bothers you, or you want something slightly more general, write a little routine to set a function as a property on another function, while binding its this to the function being attached to:
function set_func_as_func_prop ( propname, func_to_set, func_to_set_on ) {
func_to_set_on[propname] = func_to_set.bind(func_to_set_on);
}
Now you can write the function more generally
function change_offset (i) {
this.offset = i;
}
and set it on f or any other function.
set_func_as_func_prop ("change_offset", change_offset, f);
set_func_as_func_prop ("change_offset", change_offset, g);
Sort of:
function someFunction() {
return realFunction.apply(this, arguments);
}
function someFunctionA(name) {
return 'Hello, ' + name + '!';
}
function someFunctionB(name) {
return 'Goodbye, ' + name + '...';
}
var realFunction = someFunctionA;
someFunction.somePropertyFunction = function () {
realFunction = someFunctionB;
};
Sure it's possible. It's not recommended, but it's possible. For example:
function a() {
alert("a");
}
function b() {
alert("b");
}
function c() {
return c.f.apply(this, arguments);
}
c.f = a;
c.toggle = function () {
c.f = c.f === a ? b : a;
};
Now let's test it:
c(); // alerts "a"
c.toggle();
c(); // alerts "b"
See the demo: http://jsfiddle.net/LwKM3/
I want to attach a function to Function.prototype. Then I need to bind a new function to the original function's name (which I'm not sure if it's possible).
That indeed is impossible, you don't know what refers to the function. And you cannot change the internal representation of a function, which is immutable.
The only thing you can do is to create a new function and return that, to let the caller of your method use it somehow - specifically assigning it to the original variable:
somefunction = somefunction.augmentSomehow();
Your method for that will look like this:
Function.prototype.augmentSomehow = function() {
var origFn = this;
return function() {
// in here, do something special
// which might include invoking origFn() in a different way
};
};
Not sure if this helps, but I would implement described problem in following way:
// defined by somebody else - unknown to developer
var someFunction = function() {
alert("this is initial behavior");
}
someFunction(); // returns "this is initial behavior"
// defines parent object on which someFunction() is called
var parentObject = this; // returns window object (as called direclty in the
// browser)
// if you are calling someFunction from some object (object.someFunction())
// it would be:
// var parentObject = object;
// augumentThis definition
someFunction.augumentThis = function() {
var newFunction = function() {
alert("this is changed behavior");
};
parentObject.someFunction.somePropertyFunction = function() {
parentObject.someFunction = newFunction;
parentObject.someFunction();
};
};
someFunction.augumentThis(); // change function behavior
someFunction(); // "this is initial behavior"
someFunction.somePropertyFunction(); // "this is changed behavior"
someFunction(); // "this is changed behavior"
In some Javascript code (node.js specifically), I need to call a function with an unknown set of arguments without changing the context. For example:
function fn() {
var args = Array.prototype.slice.call(arguments);
otherFn.apply(this, args);
}
The problem in the above is that when I call apply, I'm change the context by passing this as the first argument. I'd like to pass args to the function being called without changing the context of the function being called. I essentially want to do this:
function fn() {
var args = Array.prototype.slice.call(arguments);
otherFn.apply(<otherFn's original context>, args);
}
Edit: Adding more detail regarding my specific question. I am creating a Client class that contains a socket (socket.io) object among other info pertaining to a connection. I am exposing the socket's event listeners via the client object itself.
class Client
constructor: (socket) ->
#socket = socket
#avatar = socket.handshake.avatar
#listeners = {}
addListener: (name, handler) ->
#listeners[name] ||= {}
#listeners[name][handler.clientListenerId] = wrapper = =>
# append client object as the first argument before passing to handler
args = Array.prototype.slice.call(arguments)
args.unshift(this)
handler.apply(this, args) # <---- HANDLER'S CONTEXT IS CHANGING HERE :(
#socket.addListener(name, wrapper)
removeListener: (name, handler) ->
try
obj = #listeners[name]
#socket.removeListener(obj[handler.clientListenerId])
delete obj[handler.clientListenerId]
Note that clientListenerId is a custom unique identifier property that is essentially the same as the answer found here.
If I understand you correctly:
changes context
| n | y |
accepts array n | func() | func.call() |
of arguments y | ???????? | func.apply() |
PHP has a function for this, call_user_func_array. Unfortunately, JavaScript is lacking in this regard. It looks like you simulate this behavior using eval().
Function.prototype.invoke = function(args) {
var i, code = 'this(';
for (i=0; i<args.length; i++) {
if (i) { code += ',' }
code += 'args[' + i + ']';
}
eval(code + ');');
}
Yes, I know. Nobody likes eval(). It's slow and dangerous. However, in this situation you probably don't have to worry about cross-site scripting, at least, as all variables are contained within the function. Really, it's too bad that JavaScript doesn't have a native function for this, but I suppose that it's for situations like this that we have eval.
Proof that it works:
function showArgs() {
for (x in arguments) {console.log(arguments[x]);}
}
showArgs.invoke(['foo',/bar/g]);
showArgs.invoke([window,[1,2,3]]);
Firefox console output:
--
[12:31:05.778] "foo"
[12:31:05.778] [object RegExp]
[12:31:05.778] [object Window]
[12:31:05.778] [object Array]
Simply put, just assign the this to what you want it to be, which is otherFn:
function fn() {
var args = Array.prototype.slice.call(arguments);
otherFn.apply(otherFn, args);
}
'this' is a reference to your function's context. That's really the point.
If you mean to call it in the context of a different object like this:
otherObj.otherFn(args)
then simply substitute that object in for the context:
otherObj.otherFn.apply(otherObj, args);
That should be it.
If you bind the function to an object and you use everywhere the bound function, you can call apply with null, but still get the correct context
var Person = function(name){
this.name = name;
}
Person.prototype.printName = function(){
console.log("Name: " + this.name);
}
var bob = new Person("Bob");
bob.printName.apply(null); //window.name
bob.printName.bind(bob).apply(null); //"Bob"
One way that you can work around the change of context that can happen in JavaScript when functions are called, is to use methods that are part of the object's constructor if you need them to be able to operate in a context where this is not going to mean the parent object, by effectively creating a local private variable to store the original this identifier.
I concede that - like most discussions of scope in JavaScript - this is not entirely clear, so here is an example of how I have done this:
function CounterType()
{
var counter=1;
var self=this; // 'self' will now be visible to all
var incrementCount = function()
{
// it doesn't matter that 'this' has changed because 'self' now points to CounterType()
self.counter++;
};
}
function SecondaryType()
{
var myCounter = new CounterType();
console.log("First Counter : "+myCounter.counter); // 0
myCounter.incrementCount.apply(this);
console.log("Second Counter: "+myCounter.counter); // 1
}
These days you can use rest parameters:
function fn(...args) {
otherFn(...args);
}
The only downside is, if you want to use some specific params in fn, you have to extract it from args:
function fn(...args) {
let importantParam = args[2]; //third param
// ...
otherFn(...args);
}
Here's an example to try (ES next version to keep it short):
// a one-line "sum any number of arguments" function
const sum = (...args) => args.reduce((sum, value) => sum + value);
// a "proxy" function to test:
var pass = (...args) => sum(...args);
console.log(pass(1, 2, 15));
I'm not going to accept this as an answer, as I'm still hoping for something more suitable. But here's the approach I'm using right now based upon the feedback on this question so far.
For any class that will be calling Client.prototype.addListener or Client.prototype.removeListener, I did added the following code to their constructor:
class ExampleClass
constructor: ->
# ...
for name, fn of this
this[name] = fn.bind(this) if typeof(fn) == 'function'
message: (recipient, body) ->
# ...
broadcast: (body) ->
# ...
In the above example, message and broadcast will always be bound to the new ExampleClass prototype object when it's instantiated, allowing the addListener code in my original question to work.
I'm sure some of you are wondering why I didn't just do something like the following:
example = new ExampleClass
client.addListener('message', example.bind(example))
# ...
client.removeListener('message', example.bind(example))
The problem is that every time .bind( ) is called, it's a new object. So that means that the following is true:
example.bind(example) != example.bind(example)
As such, the removeListener would never work successfully, thus my binding the method once when the object is instantiated.
Since you seem to want to be using the bind function as it is defined in Javascript 1.8.5, and be able to retrieve the original this object you pass the bind function, I recommend redefining the Function.prototype.bind function:
Function.prototype.bind = function (oThis) {
if (typeof this !== "function") {
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function () {},
fBound = function () {
return fToBind.apply(this instanceof fNOP && oThis
? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
/** here's the additional code **/
fBound.getContext = function() {
return oThis;
};
/**/
return fBound;
};
Now you can retrieve the original context that you called the bind function with:
function A() {
return this.foo+' '+this.bar;
}
var HelloWorld = A.bind({
foo: 'hello',
bar: 'world',
});
HelloWorld(); // returns "hello world";
HelloWorld.getContext(); // returns {foo:"hello", bar:"world"};
I was just reminded of this question after a long time. Looking back now, I think what I was really trying to accomplish here was something similar to how the React library works with its automatic binding.
Essentially, each function is a wrapped bound function being called:
function SomeClass() {
};
SomeClass.prototype.whoami = function () {
return this;
};
SomeClass.createInstance = function () {
var obj = new SomeClass();
for (var fn in obj) {
if (typeof obj[fn] == 'function') {
var original = obj[fn];
obj[fn] = function () {
return original.apply(obj, arguments);
};
}
}
return obj;
};
var instance = SomeClass.createInstance();
instance.whoami() == instance; // true
instance.whoami.apply(null) == instance; // true
Just push properties directly to the function's object and call it with it's own "context".
function otherFn() {
console.log(this.foo+' '+this.bar); // prints: "hello world" when called from rootFn()
}
otherFn.foo = 'hello';
otherFn.bar = 'world';
function rootFn() {
// by the way, unless you are removing or adding elements to 'arguments',
// just pass the arguments object directly instead of casting it to Array
otherFn.apply(otherFn, arguments);
}
to call a function at the same time it's defined, i had been using:
var newfunc = function() {
alert('hi');
};
newfunc();
is the following the correct way of combining these 2:
var newfunc = function() {
alert('hi');
}();
There could be a number of reasons you wish to do this. I'm not sure what yours are, but let me introduce a couple of favourite patterns:
Pattern #1: A singleton. The function is executed and then becomes a singleton object for use by other components of your code.
var singletonObject = new function() {
// example private variables and functions
var variable1 = {};
var variable2 = {};
var privateFunction = function() {
};
// example public functions
this.getData = function() {
return privateFunction(variable1, variable2);
};
// example initialisation code that will only run once
variable1.isInitialised = true;
};
Pattern #2: Self-executing anonymous function ... handy for sooo many reasons!
// Declare an anonymous function body.
// Wrap it in parenthesis to make it an "expression.
// Execute it by adding "();"
(function(){})();
And here's an example that also creates a namespace for your objects.
I'm using "NS" as an example namespace:
// declare the anonymous function, this time passing in some parameters
(function($, NS) {
// do whatever you like here
// execute the function, passing in the required parameters.
// note that the "NS" namespace is created if it doesn't already exist
})(jQuery, (window.NS = window.NS || {}));
You can also set the context of a self-executing function by using .call or .apply instead of the usual parenthesis, like this:
(function($){
// 'this' now refers to the window.NS object
}).call(window.NS = window.NS || {}, jQuery);
or
(function($){
// 'this' now refers to the window.NS object
}).apply(window.NS = window.NS || {}, [jQuery]);
var newfunc = function f() {
alert("hi!");
return f;
}();
Having a named function expressions allows the function to recursively call itself or, in this case, return itself. This function will always return itself, however, which might be an annoyance.
No. Your second example will immediately call the anonymous function and assign its return value to newfunc.
adamse describes an approach which appears to work. I'd still avoid the approach as the two step process is easier to read and thus will be easier to maintain.
If I understand your question correctly, give this a try:
(f = function (msg) {
msg = msg ? msg : 'default value';
alert(msg); }
)();
f('I\'m not the default value!');
You'll get two alerts, the first one will say "default value" and the second will say "I'm not the default value. You can see it in action at jsBin. Click 'preview' to make it run.
you could do like this:
o = {};
o.newfunc = ( function() {
function f() {
alert('hi');
}
f();
return {
f : f
};
}
)();
then calling the function like:
o.newfunc.f();
will also render an alert message