Function's names and properties in Javascript

Functions in Javascript are first class object and that means that they can have properties as much as objects do. So we can add properties to them.

function foo() {}
foo.prop = "Hello!";
console.log(foo.prop); // "Hello!"

However in order to add a property to a function we need to be able to refer to it. So how would you add a property to a function within the function itself?

function foo() {
 this.prop = "Hello";
}
foo();
console.log(foo.prop); // undefined

Ok, so that did not work. It didn't because the this keyword in this case refers to the global scope, and more generally it refers to the call site (where the function is invoked), and not to the function itself.

Result: running foo() we just added a property prop to the global scope. Oops!

console.log(window.prop); // "Hello!"

Are we then forced to add properties to functions only after they've been declared like in the first example? Can't we refer to the function from within in some other way?

In turns out that since we can name a function, we can use that name to create an internal reference to the function itself. We already automatically do that with function declarations.

function foo() {
 foo.prop = "Hello";
}
foo();
console.log(foo.prop); // "Hello!"

You may have noticed that property of foo prop returns undefined until the function foo is invoked.

When we use function expressions, naming a function is optional but useful for other reasons, mainly for debugging: if your functions are all anonymous it can get quite difficult to track down what part of your code caused a specific error. That's why many JS evangelists recommend to always name your functions, even in function expressions.

var foo = function foo() {
  foo.prop = "Hello!";
}
foo();
console.log(foo.prop); // Hello!

It comes fairly automatic to name a function with the same label than the variable we assign it to, like in the example above. But it doesn't need to.

You could name a function self to refer to itself, as we could do for objects and methods.

var foo = function self() {
  self.prop = "Hello!";
}
foo();
console.log(foo.prop); // "Hello!"

However, be aware that, in some browser at least, the variable self already refers to the global scope, and that can lead to confusion. So let's name the function with an alternative name, just not foo, neither self.

var foo = function bar() {
  bar.prop = "Hello!";
}
foo();
console.log(foo.prop); // "Hello!"

So that worked!

Note that at this point you can't call bar() from the outer scope because the name we assign to a function is an internal value of that specific function and it exists only within that function scope. In other words, it can't be used to refer to that function from the outer scopes.

console.log(bar.prop); // ReferenceError: bar is not defined…
There is an other caveat to be aware of. A function name can be shadowed by an homonymous internal variable.
function foo() {
  var foo = "Ciao!";
  foo.prop = "Hello!"; // fails silently, no properties allowed on a primitive
}
foo();
console.log(foo.prop); // undefined

What happened? We named the function foo. But within its scope we declare a variable foo as well. Assigning to it the string "Ciao!" we de facto create a reference to a primitive value (the string "Ciao!"). Since the variable has the same name of its function, the function cannot any longer be reached via its internal name. This dynamic is called shadowing. Internal variables shadow variables in the outer scope (clearly they also shadow the internal name of their function).

Now, when in the following line we try to assign a property prop to the internal variable foo, the assignment fails silently because we cannot assign properties to primitives.

var a = 3;
a.prop = 4;
console.log(a.prop); // undefined

When later (after run foo()) we try to log for foo.prop, we get undefined. That happens because inside the function foo, the entity foo no longer references the name of the function, but it is now an internal variable.

So what happens if I declare a homonymous variable within a function, but I don't assign any value to it?

function foo() {
  var foo;
  foo.prop = "Hello!"; // TypeError
}
foo();

The internal variable foo still shadows the function name. The error we get this time is caused by the attempt to assign a property to the primitive undefined. This error doesn't silently fail.

So, what would you use properties on functions for?

We could use them to store states. Consider this.

function counter() {
  counter.count = counter.count || 0;
  counter.count++;
  return counter.count;
}
counter(); // 1
counter(); // 2

In the code above the property count of counter is publicly accessible at any time via counter.count, so in a piece of code that simple there is the risk to override it or reset it. In Javascript it is possible to create private (internal) properties, variables, and states, using closures, and that will be material for a future article.

One last note. Since the name of a function is private, it can be used only within its proper function scope.

var f1 = function counter() {
  counter.count = counter.count || 0;
  counter.count++;
  return counter.count;
}
var f2 = function counter() {
  counter.count = counter.count || 0;
  counter.count++;
  return counter.count;
}
f1(); // 1
f1(); // 2
f2(); // 1
f1(); // 3

Here we create two functions with an identical content, however they also represent two separate entities. We can do that with function expression assigning each of them to a different variable.

Of course that wouldn't work the same with function declaration. Because doing so we would overwrite the content of the first function with the second one.

function foo() { .. }
function foo() { .. }

Neither it would work if f1 and f2 would refer to the same function.

var f1 = f2 = function counter() {
  counter.count = counter.count || 0;
  counter.count++;
  return counter.count;
}
f1(); // 1
f1(); // 2
f2(); // 3

Playing with function names and properties may have useful applications like storing states or configurable presets within a function.

Finally, note that, regarding the name of a function, there is a fundamental difference between function declaration and IIEF (Immediately invoked function expression).

function foo() {
  // something in here
}

Here foo is registered with the name foo in its local scope. So if we declare foo in the global scope, we can execute it with foo().

However, for IIEF the function name is not available in the outer scopes.

(function foo() {
  foo.pro = "something";
})();
console.log(foo.prop); // ReferenceError: foo is not defined
foo(); // ReferenceError: foo is not defined

IIEFs are an efficient method to avoiding polluting the global space. We can still use an IIEF name within the function itself, but at the same time that name is not available in the outer scope.