Can you turn an anonymous method (function) into a named method dynamically? - javascript

Given this method:
var obj = {}, obj.foo = function () {};
Is it possible to assign the method a name after it's created so it looks similar to:
var obj = {}, obj.bar = function bar() {};
The foo method is anonymous and assigned to a property. The bar method is named and assigned to a property.
Can you turn the anonymous foo method into a named foo method dynamically? Is there a property on the function object which can be set or something similar to:
obj.foo.<name> = Object.keys(obj)[0];
Without using jquery, please. Also, this is in a node server application so cross browser issues won't matter.
EDIT: The answer that worked for me is Daniel's link: How to dynamically set a function/object name in Javascript as it is displayed in Chrome. This approach also handles parameters for the function.

You cannot renane that precise instance of your anonymous function, but you can use a closure to redefine it changing its name, like this:
var obj = {};
// Anonymous function
obj.foo = function() {/* whatever */};
// Renaming...
obj.foo = (function(fn) {
return function foo() {
return fn.apply(this, arguments);
}
})(obj.foo);
// Now try in the console:
obj.foo
> function foo() {
return fn.apply(this, arguments);
}

Summarizing the two solutions found in other posts referenced above:
1) Dynamic function name in javascript?
2) How to dynamically set a function/object name in Javascript as it is displayed in Chrome
var foo, bar, name = "bar", renameFunction;
foo = function () {return "baz";}
bar = foo;
console.log(bar.name + " / " + bar()); // / baz;
//*************** Solution #1 **********************************************
renameFunction = function (name, fn) {
return (new Function("noName", "return function " + name +
"(){ return noName() };")(fn));
}
bar = renameFunction(name, foo);
console.log(bar.name + " / " + bar()); // bar / baz;
//*************** Solution #2 **********************************************
renameFunction = function (name, fn) {
return (new Function("return function (call) {return function " + name +
" () { return call(this, arguments) }; };")())(Function.apply.bind(fn));
};
bar = renameFunction(name, foo);
console.log(bar.name + " / " + bar()); // bar / baz;
They both work. The second solution is more complex, but I'm not sure yet what it adds.
UPDATE: The 2nd solution is the better one. It can handle arguments to the function which the first solution does not.

Related

Javascript - generic function to display caller function name

I'm trying to create a generic function ('displayFuncName()' for example) that I could call in different function definitions (for example 'foo()'), so it will console.log the function name ('foo' in this example).
something like:
var displayFuncName = function(){
console.log("caller function name: " + some parameter);
}
var foo = function(){
displayFuncName(); // should console log "caller function name: foo
}
I know it was asked in different ways in the past, but it seems like there was some deprecated option, and some of them just shows the 'displayFuncName' function name, which is of course not what I want.
Since arguments.callee throws an error in strict mode and arguments.caller is no longer supported, maybe something like that will be a better option for you:
Function.prototype.logName = function() {
var fn = this;
return function() {
console.log(fn.name);
return fn.apply(this, arguments);
}
}
var f = function named() {}.logName();
f(); // logs `named`
In this way, you can call the logName for every function you want to log name for when it's called.
console.log("caller is " + arguments.callee.caller.name);
Wouldn't it be easier to have the function name (or the function itself if you are to use theCallerFunction.name)?
This will give you the exact same results, just in a much easier way. It's also much less likely that .name will be depreciated.
var displayFuncName = function(callerFunc){
console.log("caller function name: " + callerFunc.name);
}
var function = foo(){
displayFuncName(foo);
}
"arguments.callee.caller.name" is depreciated I believe.
Instead of calling a generic function from every method, you can use something like
arguments.callee.caller.name
This will give you the name of the function who called your function.
If you use this in your generic method, then that will give you the name of the function in which you want to know the caller. But, if you have a common assumption that you want to know the caller of your caller, the you can use something like this.
firstFunction();
function firstFunction(){
secondFunction();
}
function secondFunction(){
whoCalled();
}
function whoCalled(){
alert("caller is " + arguments.callee.caller.arguments.callee.caller.name);
}
var displayFuncName = function(){
console.log("caller function name: " + arguments.callee.caller.name );
}
function foo(){
displayFuncName(); // should console log "caller function name: foo
}
foo();
or else if you want the whole function then you can use
var displayFuncName = function(){
console.log("caller function name: " + arguments.callee.caller.toString());
}
var foo = function(){
displayFuncName(); // should console log "caller function name: foo
}
foo();
Whichever suits your requirement.
One solution would be this:
var displayFuncName = function(o) {
console.log(o.name);
}
var foo = function(){
displayFuncName(foo);
console.log(foo.name); // also possible
}
foo();
But you can find way more solutions.
See here.

Get current function name in strict mode

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');
});

JavaScript: Scope of 'this' within a function

I'm somewhat new to JavaScript and have a few questions about scope that don't seem to have been explicitly asked about before. At the top of a function I'm working on in angular a variable vm is set equal to this. I understand that anything prefaced with vm going forward will be in scope of this however how is this different from being in the function's scope to begin with? To be more explicit, how would vm.foo = "test" differ from var foo = "test" inside of a function in terms of its scope. Any help would be much appreciated.
If you set vm = this, then properties of vm can persist beyond the scope of the current function invocation. In contrast, a local variable value (e.g., var foo = "test") does not persist past the current function invocation.
Basically, this.foo within a function is not equivalent to var foo within that same function. The first actually references a property value on the this object, whereas the second only references a local variable in the current function invocation scope.
Here's an example to illustrate this difference:
function myFunction(myArg) {
console.log("this.foo = " + this.foo);
console.log("foo = " + foo);
var foo = "test";
console.log("foo' = " + foo);
var vm = this;
console.log("vm.foo = " + this.foo);
vm.foo = myArg;
console.log("vm.foo' = " + this.foo);
}
console.log("window.foo = " + window.foo);
console.log(">>> Test call 1");
myFunction("abc");
console.log("window.foo = " + window.foo);
console.log(">>> Test call 2");
myFunction("xyz");
console.log("window.foo = " + window.foo);
For convenience, here is the console output:
window.foo = undefined
>>> Test call 1
this.foo = undefined
foo = undefined
foo' = test
vm.foo = undefined
vm.foo' = abc
window.foo = abc
>>> Test call 2
this.foo = abc
foo = undefined
foo' = test
vm.foo = abc
vm.foo' = xyz
window.foo = xyz
As you can see, this inside the function actually refers to the global window object. That means that the value of vm.foo that you assign inside the function is actually available anywhere that window is accessible (i.e., everywhere in your script). You can change what object is used as this if you invoke the function using its call method, and explicitly pass a different object as thisArg. You can also get a different object as this if you invoke the function as a method on some object. Here's an example illustrating both of these possibilities:
function myFunction(myArg) {
console.log("this.foo = " + this.foo);
console.log("foo = " + foo);
var foo = "test";
console.log("foo' = " + foo);
var vm = this;
console.log("vm.foo = " + this.foo);
vm.foo = myArg;
console.log("vm.foo' = " + this.foo);
}
var x = { f: myFunction };
var y = { f: myFunction, foo: "YYY" };
var z = { foo: "ZZZ" };
x.f("x"); // "this" is "x"
y.f("y"); // "this" is "y"
myFunction.call(z, "z"); // "this" is "z"
console.log("x.foo = " + x.foo);
console.log("y.foo = " + y.foo);
console.log("z.foo = " + z.foo);
Notice how the calls that use y and z for this have initial values of this.foo, since the corresponding objects are initialized with a value for the foo property. The value of this.foo persists in the object referenced by this, not in the function itself (unless of course this is referencing the function itself).
Inside a function, var foo = 'test' does not necessarily relate foo to this, because the value of this depends on how the function was called (see Function context).
Rather independently of the above, the reason for assigning this to vm is to keep its reference in case you want to have another function inside this function, where you refer to the original context of this. This is usually done within a controller function, see this Angular Style Guide.

Getting a 'this' reference to a 2nd level prototype function

I'm fairly certain this isn't possible, but wanted to see if anyone had some ingenious ideas as to how to make it possible.
I want the following code to work:
var x = new foo();
x.a.getThis() === x; // true
In other words, I want x.a.getThis to have a reference to this being x in this case. Make sense?
In order to get this to work one level deep is simple:
function foo(){}
foo.prototype.getThis = function(){ return this; }
var x = new foo();
x.getThis() === x; // true
One thing, I want this to work as a prototype, no "cheating" by manually binding to this:
function foo(){
this.a = {
getThis : (function(){ return this; }).bind(this)
};
}
Although the above is a perfect functional example of what I'm trying to achieve, I just don't want all the extra functions for each instance :)
FYI, the actual use case here is that I'm creating classes to represent Cassandra objects in node and I want to be able to reference a super-column --> column-family --> column via foo.a.b and keep a reference to foo in the deep function.
You can't do this without a forced bind of some kind. You say you don't want to "cheat" but this breaks the standard rules about what this is, so you have to cheat. But JS lets you cheat, so it's all good.
BTW, for what it's worth coffee script makes this so trivial.
foo = ->
#a = getThis: => this
The fat arrow => preserves the context of this for from the scope it was called in. This allows you to easily forward the context to another level.
That code gets compiled to this JS:
var foo;
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
foo = function() {
return this.a = {
getThis: __bind(function() {
return this;
}, this)
};
};
Which basically just does what you say you do not want to do.
Or if the value doesn't have to this specifically, you can set the "owner" in the child object.
var A = function(owner) {
this.owner = owner;
};
A.prototype.getThis = function() {
return this.owner;
};
var Foo = function() {
this.a = new A(this);
};
var foo = new Foo();
if (foo.a.getThis() === foo) {
alert('Happy dance');
} else {
window.location = 'https://commons.lbl.gov/download/attachments/73468687/sadpanda.png';
}
http://jsfiddle.net/4GQPa/
And the coffee script version of that because I am a passionate and unreasonable zealot for it:
class A
constructor: (#owner) ->
getThis: -> #owner
class Foo
constructor: -> #a = new A(this)
foo = new Foo()
if foo.a.getThis() is foo
alert 'Happy Dance'
else
window.location = 'https://commons.lbl.gov/download/attachments/73468687/sadpanda.png'
Impossible to do reliably without binding the value at the start since the value of a function's this is set by the call. You can't know beforehand how it will be called, or which functions need a special or restricted call to "preserve" the this -> this relationship.
The function or caller's this may be any object, there may not be a this -> this at all. Consider:
var x = {
a : {
b: function() {return this;}
}
}
When you call x.a.b(), then b's this is a. But if you do:
var c = x.a.b;
c(); // *this* is the global object
or
x.a.b.call(someOtherObject);
What is the value of this -> this in these cases?
Answering my own question because someone else may find it useful. Not sure if I'll end up going with this or Squeegy's solution. The functions are only ever defined once and then the containing object is cloned and has parent = this injected into it:
function foo(){
var self = this, nest = this.__nestedObjects__ || [];
nest.forEach(function(prop){
self[prop] = extend({ parent : self }, self[prop]);
});
}
// bound like this so that they're immutable
Object.defineProperties(foo.prototype, {
bar : {
enumerable : true,
value : {
foobar : function(){
return this.parent;
},
foo : function(){},
bar : function(){}
}
},
__nestedObjects__ : { value : ['bar'] }
});
var fooInst = new foo();
console.log(fooInst.bar.foobar() == fooInst);
or based on Squeegy's solution:
function foo(){
for(var cls in this.__inherit__){
if(!this.__inherit__.hasOwnProperty(cls)){ continue; }
this[cls] = new (this.__inherit__[cls])(this);
}
}
var clsA;
// bound like this so that they're immutable
Object.defineProperties(foo.prototype, {
__inherit__ : { value : {
bar : clsA = function(parent){
Object.defineProperty(this, '__parent__', { value : parent });
}
}
}
});
clsA.prototype = {
foobar : function(){
return this.__parent__;
}
};
var fooInst = new foo();
console.log(fooInst.bar.foobar() == fooInst);

How do I create a child class of Javascript's Function class?

I would like to create a Javascript class that I can use like so:
var f = new myFunction(arg1, arg2);
f.arg1; // -> whatever was passed as arg1 in the constructor
f();
f instanceof myFunction // -> true
typeof f // -> function
I can treat it like a normal object, even adding the native Function object to the prototype chain, but I can't call it like a function:
function myFunction(arg1, arg2) {
this.arg1 = arg1;
this.arg2 = arg2;
}
myFunction.prototype = Function
var f = new myFunction(arg1, arg2); // ok
f.arg1; // ok
f(); // TypeError: f is not a function, it is object.
f instanceof myFunction // -> true
typeof f // -> object
I can have the constructor return a function, but then it's not an instance of myFunction:
function myFunction(arg1, arg2) {
var anonFunction = function() {
};
anonFunction.arg1 = arg1;
anonFunction.arg2 = arg2;
return anonFunction;
}
var f = new myFunction(arg1, arg2); // ok
f.arg1; // ok
f(); // ok
f instanceof myFunction // -> false
typeof f // -> function
Any suggestions? I should add that I really want to avoid using new Function() since I hate string code blocks.
First and foremost, you should probably be considering some other way of doing this, because it is unlikely to be portable. I'm just going to assume Rhino for my answer.
Second, I'm not aware of any way in Javascript of assigning a function's body after construction. The body is always specified as the object is constructed:
// Normal function definitions
function doSomething() { return 3 };
var doSomethingElse = function() { return 6; };
// Creates an anonymous function with an empty body
var doSomethingWeird = new Function;
Now, there's a non-standard Mozilla extension in the form of a __proto__ property on every object. This allows you the change the inheritance chain of any object. You can apply this to your function object to give it a different prototype after construction:
// Let's define a simple prototype for our special set of functions:
var OddFunction = {
foobar: 3
};
// Now we want a real function with this prototype as it's parent.
// Create a regular function first:
var doSomething = function() {
return: 9;
};
// And then, change it's prototype
doSomething.__proto__ = OddFunction;
// It now has the 'foobar' attribute!
doSomething.foobar; // => 3
// And is still callable too!
doSomething(); // => 9
// And some of the output from your example:
doSomething instanceof OddFunction; // => true
typeof doSomething; // => function
function Foo() { var o = function() {return "FOO"}; o.__proto__ = Foo.prototype; return o; }
(new Foo()) instanceof Foo: true
(new Foo())(): FOO
This isn't possible. If it should be a instance of your function then it has to be a object. Why do you want this?
I dont know why you would want to do something like this. But here's a snippet which comes close,
function MyFunction(arg1, arg2)
{
this.firstProp = arg1;
this.secondProp = arg2;
}
var f = function(arg1, arg2) {
return new MyFunction(arg1, arg2);
}(12,13);
alert("Arg1 " + f.firstProp) // 12;
alert("Arg2 " + f.secondProp) // 13;
alert(f instanceof MyFunction) // true;
Here is what I think a more javascript way of doing what you want, except it doesn't use the instanceof for objects but an inner one.
var f = function(arg1, arg2){
return {
instanceOf:arguments.callee,
arg1:arg1,
arg2:arg2
};
};
var fn = f(1, function(p){ alert(p); });
fn.arg1; // 1
fn.instanceOf === f; //true
typeof f; //function
typeof fn; //object
fn.arg2('hello'); //show alert hello

Categories