As repeatedly said, it is considered bad practice to use the Function constructor (also see the ECMAScript Language Specification, 5th edition, § 15.3.2.1):
new Function ([arg1[, arg2[, … argN]],] functionBody)
(where all arguments are strings containing argument names and the last (or only) string contains the function body).
To recapitulate, it is said to be slow, as explained by the Opera team:
Each time […] the Function
constructor is called on a string
representing source code, the script
engine must start the machinery that
converts the source code to executable
code. This is usually expensive for
performance – easily a hundred times
more expensive than a simple function
call, for example. (Mark ‘Tarquin’ Wilton-Jones)
Though it's not that bad, according to this post on MDC (I didn't test this myself using the current version of Firefox, though).
Crockford adds that
[t]he quoting conventions of the
language make it very difficult to
correctly express a function body as a
string. In the string form, early
error checking cannot be done. […] And
it is wasteful of memory because each
function requires its own independent
implementation.
Another difference is that
a function defined by a Function
constructor does not inherit any scope
other than the global scope (which all
functions inherit). (MDC)
Apart from this, you have to be attentive to avoid injection of malicious code, when you create a new Function using dynamic contents.
That said, T.J. Crowder says in an answer that
[t]here's almost never any need for
the similar […] new Function(...),
either, again except for some advanced
edge cases.
So, now I am wondering: what are these “advanced edge cases”? Are there legitimate uses of the Function constructor?
NWMatcher — Javascript CSS selector and matcher, by Diego Perini — uses Function constructor (1, 2, 3, 4, etc.) to create ("compile") highly-efficient versions of selector matchers.
The benchmark (which I just ran on Chrome 5) speaks for itself:
Note the difference between NWMatcher and Sizzle, which is a very similar selector engine, only without function compilation :)
On a side note, ECMAScript 5 doesn't throw any errors on invocation of Function. Neither in strict, nor in "standard" modes. Strict mode, however, introduces few restrictions on presence of identifiers such as "eval" and "arguments":
You can't have declare variables/functions/arguments with such names:
function eval() { }
var eval = { };
function f(eval) { }
var o = { set f(eval){ } };
You can't assign to such identifier:
eval = { };
Also note that in strict mode, eval semantics is slightly different from that in ES3. Strict mode code can not instantiate variables or functions in the environment from which it was called:
eval(' "use strict"; var x = 1; ');
typeof x; // "undefined"
I use the new Function() constructor as an in-line JS interpreter in one of the web apps I'm developing:
function interpret(s) {
//eval(s); <-- even worse practice
try {
var f = new Function(s);
f();
}
catch (err) {
//graceful error handling in the case of malformed code
}
}
As I get stuff streaming over AJAX (not an iframe), I continuously interpret() it on readyStateChange == 3. This works surprisingly well.
Edit: here's a clear case study that shows that new Function() is categorically faster than eval(). I.e. you should never (rarely?) use eval in lieu of new Function().
http://polyfx.com/stuff/bsort.html <- the 1000 iteration version, may crash your browser
http://polyfx.com/stuff/bsort10.html <- the shorter version
Eval is on average, almost 8 times slower than new Function().
jQuery uses it to parse JSON strings when a JSON parser object is not available. Seems legit to me :)
// Try to use the native JSON parser first
return window.JSON && window.JSON.parse ?
window.JSON.parse( data ) :
(new Function("return " + data))();
John Resig used the Function constructor to create "compiled" versions of client-side templates written in an asp syntax. http://ejohn.org/blog/javascript-micro-templating/
This is a separate case from my other answer.
I used the Function constructor a while back to create custom string formatters that were being called repeatedly. The overhead of creating the function (which I take it is the performance issue you're talking about) was far outweighed by the improved performance of the custom-built functions, which were created at runtime specifically to process a particular format string, and therefore did not need to evaluate tons of irrelevant cases — or parse a format string, for that matter. It's a bit like compiling a regular expression, I suppose.
The only legitimate use I have come for it is when I wrote this:
Function.prototype.New = (function () {
var fs = [];
return function () {
var f = fs [arguments.length];
if (f) {
return f.apply (this, arguments);
}
var argStrs = [];
for (var i = 0; i < arguments.length; ++i) {
argStrs.push ("a[" + i + "]");
}
f = new Function ("var a=arguments;return new this(" + argStrs.join () + ");");
if (arguments.length < 100) {
fs [arguments.length] = f;
}
return f.apply (this, arguments);
};
}) ();
The code allows you to use Function.prototype.apply while 'using' the new keyword.
Example:
function Foo (x, y, z) {
this.x = x;
this.y = y;
this.z = z;
this.otherArgs = Array.prototype.slice.call (arguments, 3);
}
var foo = Function.prototype.New.apply (Foo, [1, 2, 3, 4, 5, 6, 7]);
// /*equiv*/ var foo = Foo.New.apply (Foo, [1, 2, 3, 4, 5, 6, 7]);
// /*equiv*/ var foo = Foo.New (1, 2, 3, 4, 5, 6, 7);
var bool = true
&& foo.x == 1
&& foo.y == 2
&& foo.z == 3
&& foo.otherArgs.length == 4
&& foo.otherArgs [0] == 4
&& foo.otherArgs [1] == 5
&& foo.otherArgs [2] == 6
&& foo.otherArgs [3] == 7
;
alert (bool);
You might want to execute a string of code more than once. Using the Function constructor means that you only have to compile it once.
You might want to pass arguments to the code, for instance if you're polyfilling an event you can retrieve the event attribute and construct a Function expecting an event argument.
You can combine the two and compile it in one location and execute it at another and still manage to pass arguments in the variables that the string of code expects.
Related
This is an edge case and probably bad practice, but it made me curious about some js internals. Can anyone explain why chrome dev tools tells me that I have created a function named a.a.b.b here?
Note that this does not happen unless you are assigning to a property. Otherwise both a and b appear to refer to a function object named 'b':
By the way, I originally encountered this here when trying to answer my own question about dat.gui.js .
This has nothing to do with the language spec.
It's a DevTools enhancement for debugging convenience, which is ported recently in Chrome.
Remember what we used to do?
function F() {}
// notice it's a NAMED function expression
F.prototype.asdf = function _asdf() { debugger; };
var f = new F();
f.asdf();
Then in breakpoint debugging, we can find the method by its name _asdf from function call stack. Otherwise it's the pain in the ass to do that from a list of (anonymous function).
In latest Chrome, when you assign an anonymous function as an object property, an alias will be attached to it.
var a = {}, b = {};
a.a = b.b = function() { debugger; };
a.b = b.a = function _abba() { debugger; };
Remember, it's just a DevTools enhancement, the method remains anonymous:
a.a.name; // ""
a.b.name; // "_abba"
But it's very helpful in breakpoint debugging:
a.a();
a.b();
EDIT:
I'm not very sure why the alias is generated as a.a.b.b, it looks very easy but kind of... stupid. However, in practice we seldom do a.a = b.b = func... thing (lucky). Instead, we define a method in one place, and do inheritence when necessary, rather than copy reference directly.
So in a good programming practice, the alias should and would exactly reflect where you define the method. For example, alias Dog.bark in breakpoint clearly maps to Dog.prototype.bark in source code, even if it's called on a Puppy instance, and we don't have to do old school named function expression.
function Dog() {}
Dog.prototype.bark = function() { alert("Woof!") }; // anonymous function expression here
function Puppy() {}
Puppy.prototype = new Dog();
(new Puppy()).bark(); // break point alias -> Dog.bark
One more thing, when I discovered this feature, I can't stop thinking of it - does it imply that Chrome will implement ES6 class very soon? How exciting!
I just started programming and I've been playing around with it. I watched a programming course on lynda.com to start out, but it didn't cover functions very well, I know what they are, but I don't know the different formats of functions or how to call them. I know how to call simple things like this:
var foo=function {
//code...
}
but I want to use more complicated things like this (I'm starting to to things with HTML):
$(document).keypress(function(e)) {
if(e.which == 13) {
alert('You pressed enter!');
}
});
or just whatever other styles there are.
There are no different formats of functions. All of them are defined with function keyword followed by arguments and body. If you have a function foo then you call it via foo(); (you can pass arguments as well, foo(1,2,3);). There are more complex ways of calling functions, for example via foo.call or foo.apply but I don't think it is necessary to talk about that here.
Note that functions in JavaScript are first class citizens. That means that they can be treated as objects. In particual you can pass them to another function. Have a look at this example:
var foo = function(fn) {
return fn()+1;
};
What happens here? foo takes a function as an argument (we know that because fn() is called in body), calls it and adds 1 to result. So if I call foo like this:
foo(function() {
return 1;
});
what would the result be? That's a simple example. Consider something more complex:
var foo = function(list, fn) {
var res = [];
for (var i = 0; i < list.length; i++) {
var mapped = fn(list[i]);
res.push(mapped);
}
return res;
};
This is a simple version of the .map method on lists. So it takes a list and a function as arguments, then applies the function to each element of the list and returns a new list:
> foo([1, 2, 3], function(el) { return -el; });
[-1, -2, -3]
It is the same as calling
> [1, 2, 3].map(function(el) { return -el; });
[-1, -2, -3]
Different ways of declaring functions
function A() {}; // function declaration
var B = function() {}; // function expression
var C = ( function() {} ); // function expression with grouping operators
var D = function foo() {}; // named function expression
var E = ( function() { // immediately-invoke function expression (IIFE) that returns a function
return function() {}
})();
var F = new Function(); // Function constructor
var G = new function() {}; // special case: object constructor
Your code is actually a good example of the different types of functions. First is $(), which represents the JQuery library--a useful add-on to JavaScript. You typically give it a string called a CSS selector, which is a way to pick out a part (or parts) of a document. In this case, you're picking out the whole document, but you could also say something like $("#logo"), which will return a document with id="logo" or $("img") will return all elements in the document.
An object in JS can be just about anything, and there are different types of objects. Each type of object has special functions available to it. These functions are called methods.
In the above example, the document object returned by $(document) has the .keypress() method available to it, which listens for a particular keypress. Keypress needs to know what to do when a key is pressed, and you do so by giving it a function as a parameter. That function will execute every time a key is pressed.
One thing that's useful to remember about JavaScript is that functions are thought of as "first-class citizens", meaning they are as good as straight-up values as far as JavaScript is concerned. So if I have a function like:
var myString = function(word)
{
return word;
}
If I do:
var myWord = "hello";
It's the same as:
var otherWord = myString("hello");
If I compare them:
var compareWords = function(word1, word2)
{
return word1 == word2;
}
var compareMyWords = compareWords(myWord, otherWord);
It's the same as saying
var compareMyWords = true;
This is important to know because it means functions can take other functions as arguments without a problem. We see that happening in the keypress method. It might be a bit hard to notice, but you can see it if you declare the function beforehand:
var keypressFunction = function(e)) {
if(e.which == 13) {
alert('You pressed enter!');
}
The following is the same as your example:
$(document).keypress(keypressFunction);
The difference is that your example uses an anonymous function. It hasn't been declared with "var" or "function", so I couldn't reuse it if I wanted to. That's not really a bad thing. Anonymous functions are very useful when you get into more advanced stuff.
Your anonymous function is allowed one parameter, an object representing the key that was actually pressed. In this case it only wants to do something if the key represented by 13 is pressed (Enter).
Finally there's the alert function, which pops up a message. Note that functions don't always have to return a value. Usually when they don't, they do something to their environment instead (otherwise what's the point). In your example only one function actually returns something--the $() function, although nothing gets done with it, but you could keep going and replace the semicolon at the end with a period and use the ready() method or whatever methods are available to the object returned by $(document). In fact, as long as you know what type of object is being returned, you could do something like:
$("#message").addClass("alert").fadeIn().delay().fadeOut();
Because each of these methods return the same object, we can do this "method chaining". jQuery purposely tries to make most of its methods return the DOM objects it acted on so that you can do this. Other libraries, like d3.js, make use of method chaining for some very cool visual transformations.
I don't think starting off using jQuery is as horrible an idea as others might advise. It's still JavaScript. It could be argued that JQuery forces you to learn advanced concepts (callbacks, CSS selectors, etc) that you could otherwise hobble by for years without knowing. I could also argue that JavaScript itself is a bad language to start with when learning to program.
Instead I'll say dive in and have fun! The ultimate purpose is to build awesome things & not get too crippled by having to do it the right way. Find a good balance between learning and building, and don't get too discouraged by the few jealous stackoverflow users who come here to snuff the joy they once had in building awesome things.
I order to know how to call different types of functions in Javascript it is important to know all JavaScript Function types. Below is a link that take you to:
All JavaScript Function Types?
I personally think you are over complicating it.
Yes, the different ways of writing a function tend to have different names (function, anonymous function, colosure, lambda,....) but in the end its all a function:
They combine several statements into one.
For example:
// Crating a function (most commomn way)
function a() {
alert('a');
};
// Creating a anonymous (nameless) function and assigning it to b
var b = function() {
alert('b');
};
var c = a;
var d = b;
var e = {};
// Creating a function that accepts a function and executes it.
// This is in essence what $(document).keypress() does
e.f = function(f){
f();
};
// Alerts: a
a();
// Alerts: b
b();
// Alerts: a
c();
// Alerts: b
d();
// Sample how you can call $(document).keypress()
// Alerts: c
e.f( function() {
alert('c');
});
// Alerts: a
e.f(a);
// Alerts: b
e.f(b);
According to the MDC, the ECMA-262, 5th edition gives the implementation of forEach as:
if (!Array.prototype.forEach)
{
Array.prototype.forEach = function(fun /*, thisp */)
{
"use strict";
if (this === void 0 || this === null)
throw new TypeError();
var t = Object(this);
var len = t.length >>> 0;
if (typeof fun !== "function")
throw new TypeError();
var thisp = arguments[1];
for (var i = 0; i < len; i++)
{
if (i in t)
fun.call(thisp, t[i], i, t);
}
};
}
Can anyone tell me what the line "var t = Object(this)" is doing? How does Object(this) differ from plain this? And what work is that difference doing here?
The Mozilla implementations just try to emulate exactly the steps that are described in the specification, Object(this); emulates the first step, calling the ToObject internal method:
From Array.prototype.forEach 15.4.4.18:
....
When the forEach method is called with
one or two arguments, the following
steps are taken:
Let O be the result of calling
ToObject passing the this value as the
argument.
Let lenValue be the result of calling the [[Get]] internal method of O with the argument "length".
Let len be ToUint32(lenValue).
....
Calling the Object constructor as a function behind the scenes it performs type conversion, internally as described in 15.2.1.1 the ToObject method is called.
There are more things like this if you look carefully, for example, the line:
var len = t.length >>> 0;
They are emulating a call to the ToUint32 internal method, as described in the step 3, using the unsigned right shift operator (>>>).
Edit:
The previous lines answer why the Mozilla implementation does it in this way.
You might wonder why the ECMAScript spec. needs to call ToObject, check back the Step 2, and it will start to seem obvious:
Let lenValue be the result of calling the [[Get]] internal method of O with the argument "length".
The spec. needs to ensure that the this value used when the function is called is an object, because primitive values don't have any internal methods, an as you can see on the step 2, the [[Get]](P) internal method is needed, to get the value of the length property.
This is done because for strict functions (and also for built-in functions), you can set primitive values as the function's this value, e.g.:
(function () {"use strict"; return typeof this; }).call(5); // "number"
While for non-strict functions, the this value is always converted to Object:
(function () { return typeof this; }).call(5); // "object"
The probable reason is s9.9 of ECMA-262, about the abstract ToObject operation (as mentioned by #CMS).
When called on null or an undefined value it forces the throwing of a TypeError, but those are already trapped by the previous lines.
However if you were to call:
Array.prototype.forEach.call("123", func() { ... } )
this would fail if it weren't for the type coercion. In particular you can't call index in this if this is a string, but you can call it on the result of ToObject.
This text from 15.4.4.18 is probably relevant:
The forEach function is intentionally generic; it does not require that its this value be an Array object. Therefore it can be transferred to other kinds of objects for use as a method. Whether the forEach function can be applied successfully to a host object is implementation-dependent.
I write var t = this; all the time. I find that the scope of this is sometimes browser-dependent; in any case it's not always clear what a browser is going to do with the keyword this as scope changes, especially in method closures. I like to dumb down my JS code to a kindergarten level to leave minimal room for individual browsers to do wonky things.
To ensure that I'm always dealing with the this I want to be dealing with when passing this to a method or something, I always write var t = this; as the first line of my method. Then, t is a variable and obeys predictable variable scope rules, and its pointer is assigned at assignment time to the object denoted by this at that time. This way I don't have to worry about a method, other object, or noncompliant browser reinterpreting what this refers to in scope.
How can I access a function name from inside that function?
// parasitic inheritance
var ns.parent.child = function() {
var parent = new ns.parent();
parent.newFunc = function() {
}
return parent;
}
var ns.parent = function() {
// at this point, i want to know who the child is that called the parent
// ie
}
var obj = new ns.parent.child();
In ES6, you can just use myFunction.name.
Note: Beware that some JS minifiers might throw away function names, to compress better; you may need to tweak their settings to avoid that.
In ES5, the best thing to do is:
function functionName(fun) {
var ret = fun.toString();
ret = ret.substr('function '.length);
ret = ret.substr(0, ret.indexOf('('));
return ret;
}
Using Function.caller is non-standard. Function.caller and arguments.callee are both forbidden in strict mode.
Edit: nus's regex based answer below achieves the same thing, but has better performance!
ES6 (inspired by sendy halim's answer below):
myFunction.name
Explanation on MDN. As of 2015 works in nodejs and all major browsers except IE.
Note: On bound functions this will give "bound <originalName>". You will have to strip the "bound " if you want to get the original name.
ES5 (inspired by Vlad's answer):
If you have a reference to the function, you can do:
function functionName( func )
{
// Match:
// - ^ the beginning of the string
// - function the word 'function'
// - \s+ at least some white space
// - ([\w\$]+) capture one or more valid JavaScript identifier characters
// - \s* optionally followed by white space (in theory there won't be any here,
// so if performance is an issue this can be omitted[1]
// - \( followed by an opening brace
//
var result = /^function\s+([\w\$]+)\s*\(/.exec( func.toString() )
return result ? result[ 1 ] : '' // for an anonymous function there won't be a match
}
I have not run unit tests on this, or verified implementation
differences, but in principle it should work, if not leave a comment.
Note: won't work on bound functions
Note: that caller and callee are considered deprecated.
[1] I include it here because it is legal and often enough syntax highlighting tools fail to take into account the white space between function name and parenthesis. On the other hand, I'm not aware of any implementation of .toString() that will include white space here, so that's why you can omit it.
As an answer to the original question, I would drop parasitic inheritance and go for some more traditional OOP design patterns. I wrote a TidBits.OoJs to comfortably write OOP code in JavaScript with a feature set mimicking C++ (not yet complete, but mostly).
I see from the comments that you would like to avoid passing information parent needs to it's constructor. I must admit that traditional design patterns won't save you from that one though, since it is generally a considered a good thing to make your dependencies obvious and enforced.
I would also suggest to steer away from anonymous functions. They only make debugging and profiling a PITA because everything just shows up as "anonymous function", and there is no benefit to them that I'm aware of.
what you're doing is assigning unnamed function to a variable. you probably need named function expression instead ( http://kangax.github.com/nfe/ ).
var x = function x() {
console.log( arguments.callee.name );
}
x();
however I'm not sure how much cross-browser that is; there's an issue with IE6 that makes you function's name leak to the outer scope. also, arguments.callee is kind of deprecated and will result in error if you're using strict mode.
It looks like the most stupid thing, that I wrote in my life, but it's funny :D
function getName(d){
const error = new Error();
const firefoxMatch = (error.stack.split('\n')[0 + d].match(/^.*(?=#)/) || [])[0];
const chromeMatch = ((((error.stack.split('at ') || [])[1 + d] || '').match(/(^|\.| <| )(.*[^(<])( \()/) || [])[2] || '').split('.').pop();
const safariMatch = error.stack.split('\n')[0 + d];
// firefoxMatch ? console.log('firefoxMatch', firefoxMatch) : void 0;
// chromeMatch ? console.log('chromeMatch', chromeMatch) : void 0;
// safariMatch ? console.log('safariMatch', safariMatch) : void 0;
return firefoxMatch || chromeMatch || safariMatch;
}
d - depth of stack. 0 - return this function name, 1 - parent, etc.;
[0 + d] - just for understanding - what happens;
firefoxMatch - works for safari, but I had really a little time for testing, because mac's owner had returned after smoking, and drove me away :'(
Testing:
function limbo(){
for(let i = 0; i < 4; i++){
console.log(getName(i));
}
}
function lust(){
limbo();
}
function gluttony(){
lust();
}
gluttony();
Result:
Chrome:
Fitefox:
This solution was creating only just for fun! Don't use it for real projects. It does not depend on ES specification, it depends only on browser realization. After the next chrome/firefox/safari update it may be broken.
More than that there is no error (ha) processing - if d will be more than stack length - you will get an error;
For other browsers error's message pattern - you will get an error;
It must work for ES6 classes (.split('.').pop()), but you sill can get an error;
Any constructor exposes a property name, which is the function name. You access the constructor via an instance (using new) or a prototype:
function Person() {
console.log(this.constructor.name); //Person
}
var p = new Person();
console.log(p.constructor.name); //Person
console.log(Person.prototype.constructor.name); //Person
This might work for you:
function foo() { bar(); }
function bar() { console.log(bar.caller.name); }
running foo() will output "foo" or undefined if you call from an anonymous function.
It works with constructors too, in which case it would output the name of the calling constructor (eg "Foo").
More info here: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/Caller
They claim it's non-standard, but also that it's supported by all major browsers: Firefox, Safari, Chrome, Opera and IE.
You can't. Functions don't have names according to the standard (though mozilla has such an attribute) - they can only be assigned to variables with names.
Also your comment:
// access fully qualified name (ie "my.namespace.myFunc")
is inside the function my.namespace.myFunc.getFn
What you can do is return the constructor of an object created by new
So you could say
var obj = new my.namespace.myFunc();
console.info(obj.constructor); //my.namespace.myFunc
You could use this, for browsers that support Error.stack (not nearly all, probably)
function WriteSomeShitOut(){
var a = new Error().stack.match(/at (.*?) /);
console.log(a[1]);
}
WriteSomeShitOut();
of course this is for the current function, but you get the idea.
happy drooling while you code
You could use Function.name:
In most implementations of JavaScript, once you have your constructor's reference in scope, you can get its string name from its name property (e.g. Function.name, or Object.constructor.name
You could use Function.callee:
The native arguments.caller method has been deprecated, but most browsers support Function.caller, which will return the actual invoking object (its body of code):
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FFunction%2Fcaller
You could create a source map:
If what you need is the literal function signature (the "name" of it) and not the object itself, you might have to resort to something a little more customized, like creating an array reference of the API string values you'll need to access frequently. You can map them together using Object.keys() and your array of strings
You can use name property to get the function name, unless you're using an anonymous function
For example:
var Person = function Person () {
this.someMethod = function () {};
};
Person.prototype.getSomeMethodName = function () {
return this.someMethod.name;
};
var p = new Person();
// will return "", because someMethod is assigned with anonymous function
console.log(p.getSomeMethodName());
now let's try with named function
var Person = function Person () {
this.someMethod = function someMethod() {};
};
now you can use
// will return "someMethod"
p.getSomeMethodName()
You can use constructor name like:
{your_function}.prototype.constructor.name
this code simply return name of a method.
as part as ECMAScript 6 you can use Function.name method
function doSomething() {}
alert(doSomething.name); // alerts "doSomething"
I know this is a old question but lately I've been facing some similar issue while trying to decorate some React Component's methods, for debugging purposes. As people already said, arguments.caller and arguments.callee are forbidden in strict mode which is probably enabled by default in your React transpiling. You can either disable it, or I've been able to come up with another hack, because in React all class functions are named, you can actually do this:
Component.prototype.componentWillMount = function componentWillMount() {
console.log('Callee name: ', this.__proto__.constructor.toString().substr(0,30));
...
}
This worked for me.
function AbstractDomainClass() {
this.className = function() {
if (!this.$className) {
var className = this.constructor.toString();
className = className.substr('function '.length);
className = className.substr(0, className.indexOf('('));
this.$className = className;
}
return this.$className;
}
}
Test code:
var obj = new AbstractDomainClass();
expect(obj.className()).toBe('AbstractDomainClass');
I had a similar problem and I solved it as follows:
Function.prototype.myname = function() {
return this.toString()
.substr( 0, this.toString().indexOf( "(" ) )
.replace( "function ", "" );
}
This code implements, in a more comfortable fashion, one response I already read here at the top of this discussion.
Now I have a member function retrieving the name of any function object.
Here's the full script ...
<script language="javascript" TYPE="text/javascript">
Function.prototype.myname = function() {
return this.toString()
.substr( 0, this.toString().indexOf( "(" ) )
.replace("function ", "" );
}
function call_this( _fn ) { document.write( _fn.myname() ); }
function _yeaaahhh() { /* do something */ }
call_this( _yeaaahhh );
</script>
If I understood what you wanted to do, this is what I do inside a function constructor.
if (!(this instanceof arguments.callee)) {
throw "ReferenceError: " + arguments.callee.name + " is not defined";
}
This will work in ES5, ES6, all browsers and strict mode functions.
Here's how it looks with a named function.
(function myName() {
console.log(new Error().stack.split(/\r\n|\r|\n/g)[1].trim());
})();
at myName (<anonymous>:2:15)
Here's how it looks with an anonymous function.
(() => {
console.log(new Error().stack.split(/\r\n|\r|\n/g)[1].trim());
})();
at <anonymous>:2:15
A simple solution to dynamically retrieve function names [like magic variables] is the use of scoped variables.
{
function parent() {
console.log(a.name);
}; let a = parent
}
{
function child() {
console.log(a.name)
}; let a = child
};
parent();//logs parent
child();//logs child
Note: Nested functions cease to be source elements, and are hence not hoisted.
Also, this technique cannot work with anonymous functions.
Just try Function.name
const func1 = function() {};
const object = {
func2: function() {}
};
console.log(func1.name);
// expected output: "func1"
console.log(object.func2.name);
// expected output: "func2"
look here: http://www.tek-tips.com/viewthread.cfm?qid=1209619
arguments.callee.toString();
seems to be right for your needs.
Easy way to get function name from within fuction you are running.
function x(){alert(this.name)};x()
you can use Error.stack to trace the function name and exact position of where you are in it.
See stacktrace.js
I asked this question a while back and was happy with the accepted answer. I just now realized, however, that the following technique:
var testaroo = 0;
(function executeOnLoad() {
if (testaroo++ < 5) {
setTimeout(executeOnLoad, 25);
return;
}
alert(testaroo); // alerts "6"
})();
returns the result I expect. If T.J.Crowder's answer from my first question is correct, then shouldn't this technique not work?
A very good question. :-)
The difference:
The difference between this and your detachEvent situation is that here, you don't care that the function reference inside and outside "the function" is the same, just that the code be the same. In the detachEvent situation, it mattered that you see the same function reference inside and outside "the function" because that's how detachEvent works, by detaching the specific function you give it.
Two functions?
Yes. CMS pointed out that IE (JScript) creates two functions when it sees a named function expression like the one in your code. (We'll come back to this.) The interesting thing is that you're calling both of them. Yes, really. :-) The initial call calls the function returned by the expression, and then all of the calls using the name call the the other one.
Modifying your code slightly can make this a bit clearer:
var testaroo = 0;
var f = function executeOnLoad() {
if (testaroo++ < 5) {
setTimeout(executeOnLoad, 25);
return;
}
alert(testaroo); // alerts "6"
};
f();
The f(); at the end calls the function that was returned by the function expression, but interestingly, that function is only called once. All the other times, when it's called via the executeOnLoad reference, it's the other function that gets called. But since the two functions both close over the same data (which includes the testaroo variable) and they have the same code, the effect is very like there being just one function. We can demonstrate there are two, though, much the way CMS did:
var testaroo = 0;
var f = function executeOnLoad() {
if (testaroo++ < 5) {
setTimeout(executeOnLoad, 0);
return;
}
alert(testaroo); // alerts "6"
// Alerts "Same function? false"
alert("Same function? " + (f === executeOnLoad));
};
f();
This isn't just some artifact of the names, either, there really are two functions being created by JScript.
What's going on?
Basically, the people implementing JScript apparently decided to process named function expressions both as function declarations and as function expressions, creating two function objects in the process (one from the "declaration," one from the "expression") and almost certainly doing so at different times. This is completely wrong, but it's what they did. Surprisingly, even the new JScript in IE8 continues this behavior.
That's why your code sees (and uses) two different functions. It's also the reason for the name "leak" that CMS mentioned. Shifting to a slightly modified copy of his example:
function outer() {
var myFunc = function inner() {};
alert(typeof inner); // "undefined" on most browsers, "function" on IE
if (typeof inner !== "undefined") { // avoid TypeError on other browsers
// IE actually creates two function objects: Two proofs:
alert(inner === myFunc); // false!
inner.foo = "foo";
alert(inner.foo); // "foo"
alert(myFunc.foo); // undefined
}
}
As he mentioned, inner is defined on IE (JScript) but not on other browsers. Why not? To the casual observer, aside from the two functions thing, JScript's behavior with regard to the function name seems correct. After all, only functions introduce new scope in Javascript, right? And the inner function is clearly defined in outer. But the spec actually went to pains to say no, that symbol is not defined in outer (even going so far as to delve into details about how implementations avoid it without breaking other rules). It's covered in Section 13 (in both the 3rd and 5th edition specs). Here's the relevant high-level quote:
The Identifier in a FunctionExpression can be referenced from inside the FunctionExpression's FunctionBody to allow the function to call itself recursively. However, unlike in a FunctionDeclaration, the Identifier in a FunctionExpression cannot be referenced from and does not affect the scope enclosing the FunctionExpression.
Why did they go to this trouble? I don't know, but I suspect it relates to the fact that function declarations are evaluated before any statement code (step-by-step code) is executed, whereas function expressions — like all expressions — are evaluated as part of the statement code, when they're reached in the control flow. Consider:
function foo() {
bar();
function bar() {
alert("Hi!");
}
}
When the control flow enters function foo, one of the first things that happens is that the bar function is instantiated and bound to the symbol bar; only then does the interpreter start processing the statements in foo's function body. That's why the call to bar at the top works.
But here:
function foo() {
var f;
f = function() {
alert("Hi!");
};
f();
}
The function expression is evaluated when it's reached (well, probably; we can't be sure some implementations don't do it earlier). One good reason the expression isn't (or shouldn't be) evaluated earlier is:
function foo() {
var f;
if (some_condition) {
f = function() {
alert("Hi (1)!");
};
}
else {
f = function() {
alert("Hi! (2)");
};
}
f();
}
...doing it earlier leads to ambiguity and/or wasted effort. Which leads to the question of what should happen here:
function foo() {
var f;
bar();
if (some_condition) {
f = function bar() {
alert("Hi (1)!");
};
}
else {
f = function bar() {
alert("Hi! (2)");
};
}
f();
}
Which bar gets called at the beginning? The way the specification authors chose to address that situation was to say that bar is not defined in foo at all, hence side-stepping the issue entirely. (It's not the only way they could have addressed it, but it seems to be the way they chose to do so.)
So how does IE (JScript) process that? The bar called at the beginning alerts "Hi (2)!". This, combined with the fact we know two function objects are created based on our other tests, is the clearest indication that JScript processes named function expressions as function declarations and function expressions, because that's exactly what is supposed to happen here:
function outer() {
bar();
function bar() {
alert("Hi (1)!");
}
function bar() {
alert("Hi (2)!");
}
}
There we have two function declarations with the same name. Syntax error? You'd think so, but it isn't. The specification clearly allows it, and says that the second declaration in source code order "wins." From Section 10.1.3 of the 3rd edition spec:
For each FunctionDeclaration in the code, in source text order, create a property of the variable object whose name is the Identifier in the FunctionDeclaration...If the variable object already has a property with this name, replace its value and attributes...
(The "variable object" is how symbols get resolved; that's a whole 'nother topic.) It's just as unambiguous in the 5th edition (Section 10.5), but, um, a lot less quotable.
So it's just IE, then?
Just to be clear, IE isn't the only browser that has (or had) unusual handling of NFEs, although they're getting pretty lonely (a pretty big Safari issue has been fixed, for instance). It's just that JScript has a really big quirk in this regard. But come to that, I think it actually is the only current major implementation with any really big issue — be interested to know of any others, if anyone knows of them.
Where we stand
Given all of the above, for the moment, I stay away from NFEs because I (like most people) have to support JScript. After all, it's easy enough to use a function declaration and then refer to it later (or indeed, earlier) with a variable:
function foo() { }
var f = foo;
...and that works reliably across browsers, avoiding issues like your detachEvent problem. Other reasonable people solve the problem differently, just accepting that two functions will get created and trying to minimize the impact, but I don't like that answer at all because of exactly what happened to you with detachEvent.
Well, it will work, the problem with JScript (IE), is that the identifier of the function expression (executeOnLoad) will leak to its enclosing scope, and actually creating two function objects..
(function () {
var myFunc = function foo () {};
alert(typeof foo); // "undefined" on all browsers, "function" on IE
if (typeof foo !== "undefined") { // avoid TypeError on other browsers
alert( foo === myFunc ); // false!, IE actually creates two function objects
}
})();