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');
});
Related
I would like to redefine a prototype, but still use the original prototype function. The purpose is to add test bench debug code to an existing production prototype definition.
// production definition
function tester(n) { this.name = n ; }
tester.prototype.getName = function() { return this.name; }
// debug override
if (typeof tester.prototype.getName === 'function') {
var f = tester.prototype.getName;
tester.prototype.getName = function () {
return f() + " (plus some more)";
};
}
// test
var tt = new tester('testing');
console.log(tt.getName()); // logs ' (plus some more)' but I want 'testing (plus some more)'
Naturally, my production prototypes are much more complex, and I would rather not embed my test bench code in the production code.
Many thanks in advance! - John :)
You have to call f with the correct this value and the correct arguments:
f.apply(this, arguments);
Learn more about this and apply.
This seems to be a very fragile approach though because it also requires you to know what kind of value the original method returns and what calling code is doing with it.
But I guess you are only doing this for very specific methods.
In your redefinition, you need to set the proper context (this) for the f function using Function.prototype.apply(). In your code, the context of the f function is set to the global scope, even when it is called in the redefined getName property of tt. Instead, it should be the context of the redefined getName function.
// production definition
function tester(n) { this.name = n ; }
tester.prototype.getName = function() { return this.name; }
// debug override
if (typeof tester.prototype.getName === 'function') {
var f = tester.prototype.getName;
// Here, 'this' is the global scope (window).
console.log('Global scope:');
console.log(this);
console.log('f called with context of global scope:');
console.log(f()); // prints 'name' prop of global scope
tester.prototype.getName = function () {
console.log("Instance:");
console.log(this);
// Here, 'this' is tt when tt.getName() is evaluated.
// If we call f() here, the context for f
// will still be the global scope, instead of tt.
// So, we use apply to set the context of f to
// an instance of tester.
return f.apply(this) + " (plus some more)";
};
}
// test
var tt = new tester('testing');
console.log(tt.getName()); // logs testing (plus some more)'
http://jsfiddle.net/a27xzqc9/3/
Extending Felix and Patrick's answer with encapsulation to avoid using the global variable "f", since I will be reusing this structure several times.
;(function(){
if (typeof tester.prototype.getName === 'function') {
var f = tester.prototype.getName;
tester.prototype.getName = function () {
return f.apply(this) + " (plus some more)";
};
}
})();
I'm trying to determine wether a function in javascript is a simple, plain (anonymous) function, or a constructor ( a function with a prototype ). So far, I've come up with the following function:
function isPlainFunction(value) {
var own = Object.getOwnPropertyNames(value.prototype),
ctorIndex = own.indexOf('constructor');
if ( ctorIndex !== -1 ) {
own.splice( ctorIndex, 1);
}
if (own.length) {
return false;
}
// walk prototype chain
var proto = Object.getPrototypeOf(value.prototype);
if (proto === Object.prototype) {
return true;
}
return isPlainFunction(proto);
}
I'm only targeting ES5, (node.js) but I am uncertain whether this covers all edge cases, or if there's still something I havent found regarding this subject.
I have (roughly) the following testcases in mind:
assert.ok( isPlainFunction(function(){}) );
var bar = function(){};
bar.prototype = { get one(){ return 1 } };
assert.equal( isPlainFunction(bar), false );
var foo = function(){};
foo.prototype = Object.create( bar );
assert.equal( isPlainFunction(bar), false );
That is, any function that has a prototype or inherited a prototype from one of the not-native types...
If what you are trying to test for is whether or not a function should be used as a constructor, then unfortunately this cannot be accurately determined.
You can invoke the new operator on any function, whether intended to be used that way or not without issues.
If I have this method, for instance:
function doSomethingWithThisObject(someValue) {
this.someVariable = someValue;
}
Which has the following prototype:
doSomethingWithThisObject.prototype = { prototypeVariable : 'I came from prototype' };
I could use it in the following ways:
// Use my function as a constructor:
var obj = new doSomethingWithThisObject('hi there!');
console.log(obj.someVariable); // prints "hi there!"
console.log(obj.prototypeVariable); // prints "I came from prototype"
// Use my function in an object:
var myObject = {
doSomething : doSomethingWithThisObject
};
myObject.doSomething('hi again!');
console.log(myObject.someVariable); // prints "hi again!"
console.log(myObject.prototypeVariable); // prints "undefined"
// Use my function to change global state:
doSomethingWithThisObject('you owe me ice cream!');
console.log(someVariable); // prints "you owe me ice cream!"
console.log(prototypeVariable); // prints "undefined"
Determining whether or not one of those use cases is the correct one is impossible unless the intention is specified somewhere in the code.
Some people suggest to name constructor methods with an uppercase first letter to determine that they should be used as constructors. If you decide for this suggestion with your project's coding guidelines, you could simply check if the function's name begins with an uppercase letter which would denote that the person who wrote the function intends for it to be used as a constructor.
As Ben Barkay has said, any function can become a constructor in JS through the new keyword. Behind the scenes all new is doing is setting the function's context -- you can see this with a simple test:
function test() {
console.log(this)
}
test()
output: Window {top: Window, window: Window…}
new test()
output: test {}
test {}
In JS all you need to make a function a constructor is a new keyword, and all a new does is set the function's this variable. So any function can become a constructor.
Distinguishing an anon function is easier: if it doesn't have a name, it's anonymous:
//anon:
(function() {
console.log("I'm anon")
})()
var anon = function() {
console.log("I, too, am anon")
}
If you programmatically need the function's name, you can get it through function.name
To determine whether a function does not have an extended prototype, e.g. can be assumed to be more then a plain function, the following function would return false:
function isPlainFunction(value) {
if (typeof value !== 'function') {
return false;
}
var own = Object.getOwnPropertyNames(value.prototype);
if ( own.length >= 2 || ( own.indexOf('constructor') < 0 && own.length >= 1 ) ) {
return false;
}
return Object.getPrototypeOf(value.prototype) === Object.prototype;
}
When I use var keyword to declare any variable it gets declared inside the enclosing scope. However in the code below, I have declared function c (inside an object method a.b) with var keyword and still this inside the function c is bound to the global object window. Why is this?
var a = {
b: function () {
var c = function () {
return this;
};
return c();
}
};
document.write(a.b()); //prints: [object Window]
The value of this is determined by context, not scope.
When you call a function without any context (context.func()) as you do there (c()), the default context is the default object (which is window in browsers) unless you are in strict mode (in which case it is undefined instead).
(There are exceptions to this rule, such as apply, call, bind, and new but none of them apply here).
Many people get confused by this. The value this depends on one of 4 methods of invocation.
However, functional invocation and method-invocation cause most of the confusion.
If a function is a member of an object, this is the object itself.
obj.someFunction(); //method invocation
If a function is called without context this is the global object (in 'strict mode' this is undefined.)
someFunction(); //functional invocation
The confusion occurs when a function is called within an object, but not as a member of the object as in anObject.testWithHelper(..);
var testForThis = function(isThis, message) {
//this can be confusing
if(this === isThis)
console.log("this is " + message);
else
console.log("this is NOT " + message);
};
//functional invocation
testForThis(this, "global"); //this is global
var anObject = {
test: testForThis, //I am a method
testWithHelper: function(isThis, message) {
//functional invocation
testForThis(isThis, message + " from helper");
}
};
//method invocation
anObject.test(anObject, "anObject"); //this is anObject
//method invocation followed by functional invocation
anObject.testWithHelper(anObject, "an object"); //this is NOT anObject from helper
Here is my JSFIDDLE
If you would like c to return a, you can use closure:
var a = {
b: function () {
var that = this;
var c = function () {
return that;
};
return c();
}
};
Or avoid this all together:
var getNewA = function() {
var newA = {};
newA.b = function() {
var c = function() {
return newA;
};
return c();
};
return newA;
};
var newA = getNewA();
I want to be able to assign a property to a function inside the function itself. I do not want to assign it to the object of invocation. So I want the equivalent of doing this:
var test = function() {
return true;
};
test.a = 'property on a function';
alert(test.a);
Instead of this, where the property is assigned to a global object:
var testAgain = function() {
this.a = "this property won't be assigned to the function";
return true;
};
testAgain();
alert(window.a);
Edit: To clarify, I'm wondering if there's something like this:
var test = function() {
function.a = 'property on a function';
};
alert(test.a); // returns 'property on a function'
Without knowing that the function is called test or having to execute it.
I know of course this isn't valid syntax
[is there a way to set a property on a function] without knowing that the function is called test or having to execute it.
Emphasis mine.
You can set a property on a function without knowing what its global variable name is necessarily going to be, however you do have to have a reference to the function in one way or another.
The module pattern is as close of a fit as I can think of:
window.test = (function () {
//the function could be named anything...
function testFn() {
...code here...
}
//...so long as the same name is used here
testFn.foo = 'bar';
return testFn;
}());
window.test.foo; //'bar'
The outer closure prevents testFn from being accessed anywhere globally, so all other references will have to use window.test.
This part of the answer is associated with the prior version of the question.
The simplest way of doing this is to use a named function:
var test = function testFn() {
testFn.foo = 'bar';
return true;
};
test.foo; //undefined
test();
test.foo; //'bar'
A better way of doing this is to use the module pattern so that you don't accidentally create issues with global leakage:
var test = (function () {
function ret() {
ret.foo = 'bar';
return true;
}
return ret;
}());
test.foo; //undefined
test();
test.foo; //'bar'
var testAgain = function() {
arguments.callee.a = "this property won't be assigned to the function";
return true;
};
testAgain();
alert(testAgain.a);
You can do this by simple using the name to assign the property like this:
var test = function () {
test.a = 'a';
return true;
};
When test is invoked, the property will be set.
Demo
You could use arguments.callee, as su- said, but that's considered really bad practice. Also, it won't work in strict mode.
var test = function() {
test.a = 'a';
};
Or you can use prototypes, read more here.
Consider this piece of code
var crazy = function() {
console.log(this);
console.log(this.isCrazy); // wrong.
}
crazy.isCrazy = 'totally';
crazy();
// ouput =>
// DOMWindow
// undefined
From inside crazy() 'this' refers to the window, which I guess makes sense because normally you'd want this to refer to the object the function is attached to, but how can I get the function to refer to itself, and access a property set on itself?
Answer:
Don't use arguments.callee, just use a named function.
"Note: You should avoid using arguments.callee() and just give every function (expression) a name." via MDN article on arguments.callee
I think you are asking for arguments.callee, but it's deprecated now.
https://developer.mozilla.org/en/JavaScript/Reference/Functions_and_function_scope/arguments/callee
var crazy = function() {
console.log(this);
console.log(arguments.callee.isCrazy); // right.
}
crazy.isCrazy = 'totally';
crazy();
// ouput =>
// DOMWindow
// totally
As rfw said, this is the most straight forward way to go if the function has one single name:
var crazy = function() {
console.log(crazy);
console.log(crazy.isCrazy);
};
crazy.isCrazy = 'totally';
crazy();
In case it may have different names, or you wanted to pass it around, it must be wrapped in a closure:
var crazy = (function(){
var that = function() {
console.log(that);
console.log(that.isCrazy);
};
return that;
})();
crazy.isCrazy = 'totally';
crazy();
Bind the function to itself (taking a hint from answers by #ArunPJohny and #BudgieInWA):
crazy = crazy.bind(crazy);
This will give you access from the function to its properties via this.
> crazy()
function () {
console.log(this);
console.log(this.isCrazy); // works now
}
This seems like a better solution than the accepted answer, which uses the callee feature which is deprecated and doesn't work in strict mode.
You could also now have the function call itself recursively with this() were you so inclined.
We will call this self-thisifying. Write a little utility function:
function selfthisify(fn) { return fn.bind(fn); }
crazy = selfthisify(crazy);
crazy();
Or, if you prefer more "semantic" names, you could call it accessOwnProps.
If you're a syntactic sugar type of person, you could add a selfthisify property to the Function prototype:
Object.defineProperty(Function.prototype, 'selfthisify', {
get: function() { return this.bind(this); }
});
Now you can say
crazy.selfthisify();
You have to give it its own name, so:
var crazy = function() {
console.log(crazy);
console.log(crazy.isCrazy);
}
crazy.isCrazy = 'totally';
crazy();
The variable this is only applicable in the scope of an object, for instance, if you invoked your version of the crazy function with crazy.call(crazy), it will call the function in the context of the function crazy and all would be well.
This has to deal with the scope of the function crazy. If can pass any scope to a function using the function call().
Instead of
crazy();
Use
crazy.call(crazy);
For details refer
http://odetocode.com/blogs/scott/archive/2007/07/05/function-apply-and-function-call-in-javascript.aspxhttps://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/Callhttp://devlicio.us/blogs/sergio_pereira/archive/2009/02/09/javascript-5-ways-to-call-a-function.aspx
You can use the call method
var crazy = function() {
console.log(this);
console.log(this.isCrazy);
}
crazy.isCrazy = 'totally';
crazy.call(crazy);
// calls crazy using crazy as the target, instead of window:
// functionToCall.call(objectToUseForThis);
Though if your function only ever has one name, you can do this:
var crazy = function() {
console.log(crazy);
console.log(crazy.isCrazy);
}
crazy.isCrazy = 'totally';
crazy();
Easiest way to make the function itself available in its body is to do
var crazy = function crazy2() { crazy2(); }, it's okay for crazy and crazy2 to have the same name since the first occurrence is the name in the outer scope and the second is the name in the function body.
Or simply do function crazy() { crazy(); } which will define crazy in both scopes.
how can I get the function to refer to
itself?
The idea of 'itself' does not exist with functions. What you need is an object and not just a function. An object has knowledge of itself available through the keyword 'this'. Within a function, 'this' points to the global object - in this case the window object. But if you use your function as a constructor function to create an object (using the new operator) then the object's 'this' pointer will point to the object itself.
i.e this points to the object if you write:
var anObject = new crazy();
So you can re-write your code as follows:
var crazy = function() {
this.printMe = function(){
console.log(this);
console.log(this.isCrazy);
}
}
var anObject = new crazy(); //create an object
anObject.isCrazy = 'totally'; //add a new property to the object
anObject.printMe(); //now print
In case you wish to add the property before the object is created, then you have to add the property to the function's prototype as follows:
var crazy = function() {
console.log(this);
console.log(this.isCrazy);
}
crazy.prototype.isCrazy = 'totally'; //add the property to the function's prototype
var anObject = new crazy(); //invoke the constructor
See more on my blog for a detailed explanation of these concepts with code-samples.
Are you actually trying to create an object 'class'?
function crazy(crazyState) {
this.isCrazy = crazyState;
console.log(this);
console.log(this.isCrazy);
}
crazy.prototype.alertMe = function() { alert('I am '+ this.isCrazy +' crazy.'); }
var crazyObj = new crazy('totally');
crazyObj.alertMe();
crazyObj.isCrazy = 'not';
crazyObj.alertMe();
Funny that you should ask, mate. I just went through this same issue for a different purpose. The quick version of the final code is:
$a = function() {};
$ = function() {
if (!(this instanceof $)) {
return new $();
}
this.name = "levi";
return this;
};
//helper function
var log = function(message) {
document.write((message ? message : '') + "<br/>");
};
log("$().name == window.name: " + ($().name == window.name)); //false
log("$().name: " + $().name); //levi
log("window.name: " + window.name); //result
log();
log("$a instanceof $: " + ($a instanceof $)); //false
log("typeof $a: " + (typeof $a)); //function
log("typeof $: " + (typeof $)); //function
The critical piece:
if (!(this instanceof $)) {
return new $();
}
If this isn't pointing to an object of the right type, then it makes a new one, which will properly scope this. The rest of the code is just there for verification that it does indeed work as intended.
In order to make you code to work follow below
function crazy_object (crazy) {
this.isCrazy = crazy
}
var create_crazy = new crazy_object('hello') //creating object
console.log(create_crazy); //=> { isCrazy = 'hello' }
var crazy = function() {
console.log(this); //=> { isCrazy = 'totally' }
console.log(this.isCrazy); //=> 'totally'
}
create_crazy.isCrazy = 'totally'; //=> isCrazy = 'totally'
//below we pass the created object in function crazy.
//And doing that we can use the keywork `this` and refer to the object
crazy.call(create_crazy, null);
Using the call and apply method we can pass to a function a
property,and in that function we can use the property with the keyword this
For example:
function speak (message) {
console.log(`A person with name ${this.name} say ${message}`);
}
speak.call({ name: 'Roland' }, 'Javascript is awesome');
To use it with property:
function speak (message) {
console.log(`A person with name ${this.name} say ${message}`);
}
var name = 'Roland'
speak.call({ name }, 'Javascript is awesome');